Akavall Akavall - 3 years ago 102
Scala Question

Implicit conversion from Array to WrappedArray does not happen when pattern matching

In this example:

scala> val a: Seq[Int] = Array(1,2,3)
a: Seq[Int] = WrappedArray(1, 2, 3)


Implicit conversion happens, and
Array
is converted to
WrappedArray
that extends
Seq
, as explained here: Arrays Scala Doc

but here:

object MyObject {

def main(args: Array[String]): Unit = {

val a = Array(1,2,3)
// val a: Seq[Int] = Array(1,2,3) if added explicitly works

val result = a match {
case Seq(
first,
second,
third
) => (first, second, third)
}
println(result)
}
}


The code fails with:

Error:(9, 15) scrutinee is incompatible with pattern type;
found : Seq[A]
required: Array[Int]
case Seq(


The implicit conversion does not happen, Why?

Answer Source

Burak Emir gave a rationale for the language design decision of disallowing implicit conversions in pattern matching (the following is quoted from www.scala-archive.org):

1) Type checking patterns relies on static information (like everywhere else in the compiler). In the case of patterns, an "expected type" is propagated down, in order to type variable binding patterns and more generally verify that the pattern is something that makes sense. The expected type starts, of course, with the scrutinee (aka the selector expression aka what is matched upon).

2) The translation of pattern matching uses (almost) every means possible to avoid redundant type tests. This means, that the cases present in the source code get "compressed" into a sort of decision tree diagram. This later gets translated to code.

Enter implicit conversions. Having the scrutinee be of a different type then the patterns means we cannot make use of expected type in patterns. Consequently, we would have to type check patterns independently of the type of the scrutinee.

This alone might still be feasible (careful here, who can foresee hairy interactions with sequence patterns etc). We could say, patterns have a type independent of the expected type, and type checking will see whether the type of the scrutinee complies with the pattern types (possibly after applying some implicit conversion).

But this turns out to be a non-specification.

implicit def fbTypeToFoo ... 
implicit def fbTypeToBar ... 

fb match { 
  case Foo(...) => 
  case Bar(...) => 
} 

What seems to really be needed is to apply the views "by need", meaning "inside" the pattern match.

This clashes with the present algorithm doing task 2). In presence of implicit conversions, the task of pattern matching is in fact pushed one level deeper, as the outermost pattern will always match (there's a conversion after all). This is quite annoying to implement and to specify, because patterns with and patterns without implicit conversion from the scrutinee type might be mixed, like in

implicit def FooToBar... 
myFoo match { 
  case Foo(...) 
  case Bar(... ) 
  case Foo( ...) 
} 

The assumption that a top-level "Foo" would never enter the "Bar" case is now invalid (there's a conversion after all). One basically loses all hope of optimizing for the outermost level. While the current matcher would join the remainder of patterns 1 and 3, a hypothetical matcher with implicit calls could not be designed to do so, as it would violate the first match policy.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download