WestCoastProjects
WestCoastProjects

Reputation: 63172

Any means to allow differing counts of source/target parameters in a destructuring extractor

Normal successful) case: correct number of target variables for destructuring:

scala> val arr = Array("aa","bb",1,2,3,4,5)
scala> val Array(a,b,one,two,three,four,five) = arr
a: Any = aa
b: Any = bb
one: Any = 1
two: Any = 2
three: Any = 3
four: Any = 4
five: Any = 5

Unsupported (?) Cases

a) Fewer target variables for the destructuring: the intention would be to capture the "other" parameters into one Sequence-Like variable:

scala> val arr = Array("aa","bb",1,2,3,4,5)
arr: Array[Any] = Array(aa, bb, 1, 2, 3, 4, 5)
val Array(a,b,one,two, others) = arr
scala.MatchError: [Ljava.lang.Object;@146a8d2 (of class [Ljava.lang.Object;)
        at .<init>(<console>:12)
        at .<clinit>(<console>)
        at .<init>(<console>:7)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)

b) More target variables than source variables for the destructuring: intention would be to have optional source variables

scala> val arr = Array("aa","bb",1,2,"optional-1","optional-2")
arr: Array[Any] = Array(aa, bb, 1, 2, optional-1, optional-2)

scala> val Array(a,b,one,two,optional1) = arr
scala.MatchError: [Ljava.lang.Object;@151c590 (of class [Ljava.lang.Object;)
        at .<init>(<console>:12)
        at .<clinit>(<console>)
        at .<init>(<console>:7)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)
        at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983)

Upvotes: 1

Views: 58

Answers (1)

drstevens
drstevens

Reputation: 2913

List has a deconstructing :: operator which provides support for a)

scala> val l = List("aa","bb",1,2,"optional-1","optional-2")
l: List[Any] = List(aa, bb, 1, 2, optional-1, optional-2)

scala> val a :: b :: one :: two :: others = l
a: Any = aa
b: Any = bb
one: Any = 1
two: Any = 2
others: List[Any] = List(optional-1, optional-2)

The issue with providing this operator for other data structures in standard library is that other data structures do not have similar performance characteristics. Take a similarly defined operator against Vector.

object :#: {
  def unapply[A](a: Vector[A]): Option[(A, Vector[A])] =
    if (a.length > 1) Some(a(0) -> a.drop(1))
    else None
}

scala> val a :#: b :#: one :#: two :#: others = v
a: Any = aa
b: Any = bb
one: Any = 1
two: Any = 2
others: Vector[Any] = Vector(optional-1, optional-2)

I don't necessarily promote this, but you could define a similar operator which provides support for use case b)

object :?: {
  def unapply[A](l: List[A]): Option[(Option[A], List[A])] =
    l match {
      case Nil => Some(None -> Nil)
      case a :: tail => Some(Some(a) -> tail)
    }
}

scala> val l = List("aa","bb")
l: List[String] = List(aa, bb)

scala> val a :?: optional1 :?: optional2 :?: rest = l
a: Option[String] = Some(aa)
optional1: Option[String] = Some(bb)
optional2: Option[String] = None
rest: List[String] = List()

Upvotes: 1

Related Questions