Although “avoid Array except for performance-sensitive code” is a nice drum beat, it’s still somewhat true that the Java-derived main
entry point takes Array[String]
.
It’s unfortunate that array is a simple concept, with intuitive support in certain languages, but hits a wall in Scala.
TIL there was a SID
for Array, which begins:
Arrays have turned out to be one of the trickiest concepts to get right in Scala.
That document includes interesting ancient history about pre-2.8 Array
, with compiler support, an era that deserves a special designation, much as we say, “antediluvian”.
I just noticed that I called array a “concept”, then went to read the docs where the SID
also calls it a concept. It is not just an artifact or an implementation detail. It has a special status in our mental apparatus.
The overview page is also informative about the current solution, but doesn’t happen to cover destructuring. The API Scaladoc is a compressed version.
Some of the machinery for the construction made visible:
scala> "z" +: Array("a") // print
{
val rassoc$1: String("z") = "z";
scala.Predef.refArrayOps[String](scala.Array.apply[String]("a")(scala.reflect.`package`.materializeClassTag[String]())).+:[String](rassoc$1)(scala.reflect.`package`.materializeClassTag[String]())
} // : Array[String]
The annoying part about
scala> val x +: rest = res0
^
error: scrutinee is incompatible with pattern type;
found : C with scala.collection.SeqOps[A,CC,C]
required: Array[String]
scala> val x +: rest = res0: collection.ArrayOps[String]
^
error: scrutinee is incompatible with pattern type;
found : C with scala.collection.SeqOps[A,CC,C]
required: scala.collection.ArrayOps[String]
granting that the Scaladoc for ArrayOps
warns
Neither Array
nor ArrayOps
are proper collection types
is that the best you can do is commit to ArraySeq
:
scala> val x +: rest = res0.toSeq
val x: String = z
val rest: Seq[String] = ArraySeq(a)
scala> val x +: rest = res0: Seq[String]
^
warning: method copyArrayToImmutableIndexedSeq in class LowPriorityImplicits2 is deprecated (since 2.13.0): Implicit conversions from Array to immutable.IndexedSeq are implemented by copying; Use the more efficient non-copying ArraySeq.unsafeWrapArray or an explicit toIndexedSeq call
val x: String = z
val rest: Seq[String] = ArraySeq(a)
Elsewhere, the balancing act allows me to choose whether I’d like to “transiently” view the array as a seq, but keep my array type.
This would fall in the same ball park:
scala> Array(42) match { case Nil => 1 case _ => 2 }
^
error: type mismatch;
found : collection.immutable.Nil.type
required: Array[Int]
scala> Seq(42) match { case Nil => 1 case _ => 2 }
val res2: Int = 2
That is, this is a matter of convenience. “I’m comfortable with +:
to give me the head and tail. I’m not terribly concerned with performance, but main
gave me an Array
and also I’m calling an API that also takes an Array
. I just want simple code to work simply without any head scratching. If pattern matching can paper over some seams without the wallpaper peeling, that would be great.”