Sunday, November 4, 2012

Scala: when you wish that Seq was a List

As a long-time Java dev, it is tempting to declare function parameters as Lists. This is appropriate if we require an ordered sequence, but usually we only care that we can iterate over it. Our functions are more general if they accept any Seq. [1]

However, now and then I really miss the cons operator and deconstructor pattern (::) that is defined on List. An excerpt:

   case Nil => Nil
   case head :: tail => something(head) :: recurse(tail)

If what I'm matching is a sequence instead of list, I can't use :: in either context. Here is the equivalent for a sequence:

    case Seq() => Seq()
    case Seq(head, tail @ _*) => something(head) +: recurse(tail)
  • cons :: is replaced by prepend +: 
  • The sequence deconstruction pattern _* matches 0 or more sequence elements after the first one[2]
  • Meanwhile, the @ operator links an identifier to a portion of the pattern, capturing the rest of the sequence in tail.
  • The empty sequence is equivalent to Nil in List.
Lists are prettier, but sequences are more general. Consider both when defining your methods.

[1] Technically we could be declaring the argument as GenIterable, but we're not that hard-core. 
[2] google unapplySeq to learn more about _*

No comments:

Post a Comment