4

I want to understand the mechanism behind the following line:

 val List(x) = Seq(1 to 10)

What is the name of this mechanism? Is this the same as typecasting, or is there something else going on? (Tested in Scala 2.11.12.)

6

I suspect that your problem is actually the expression

Seq(1 to 10)

This does not create a sequence of 10 elements, but a sequence containing a single Range object. So when you do this

val List(x) = Seq(1 to 10)

x is assigned to that Range object.

If you want a List of numbers, do this:

(1 to 10).toList

The pattern List(x) will only match if the expression on the right is an instance of List containing a single element. It will not match an empty List or a List with more than one element.

In this case it happens to work because the constructor for Seq actually returns an instance of List.

  • This makes sense to me, but I still don't quite grok it. For example, why does val List(x) = Seq(1 to 10) run but val List(x) = Seq(1, 2) throws a MatchError? – Stijn Apr 17 at 8:03
  • Because List(x) is a constructor pattern matching for a List which, hold one element on which x is match against. Seq(1, 2) is a Seq which holds two elements and thus can't be successfully matched with the foresaid pattern. – Benjamin Vialatou Apr 17 at 8:09
  • In case you need more example, if you try val List(x, y) = Seq(1, 2) and val List(x) = Seq(1), it'll work because you have the right number of elements. – Benjamin Vialatou Apr 17 at 8:23
  • 2
    The right word would be "pattern", not an "expression". I think it's better to distinguish those two things in this context. – Andrey Tyukin Apr 17 at 12:15
  • @AndreyTyukin Yes, thanks for fixing that for me. – Tim Apr 17 at 17:23
7

The mechanism is called Pattern Matching.

Here is the official documentation: https://docs.scala-lang.org/tour/pattern-matching.html

This works also in for comprehensions:

for{
 People(name, firstName) <- peoples
} yield s"$firstName $name"

To your example:

val List(x) = Seq(1 to 10)

x is the content of that List - in your case Range 1 to 10 (You have a list with one element).

If you have really a list with more than one element, that would throw an exception

val List(x) = (1 to 10).toList // -> ERROR: undefined

So the correct pattern matching would be:

val x::xs = (1 to 10).toList

Now x is the first element (head) and xs the rest (tail).

  • Thank you for your answer. The mechanism makes sense to me in a pattern matching context, but I'm not still not 100% sure how I should read the code line in my post. I also don't understand why, after running the above line, the type of x is scala.collection.immutable.Range.Inclusive, and not List[scala.collection.immutable.Range.Inclusive]. – Stijn Apr 17 at 7:52
  • 1
    see my updated answer – pme Apr 17 at 8:07
5

This technique is called object destructuring. Haskell provides a similar feature. Scala uses pattern matching to achieve this.

The method used in this case is Seq#unapplySeq: https://www.scala-lang.org/api/current/scala/collection/Seq.html

3

You can think of

val <pattern> = <value>
<next lines>

as

<value> match {
  case <pattern> => 
    <next lines>
}

This doesn't happen only when <pattern> is just a variable or a variable with a type.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.