Irrefutable destructuring patterns


#1

Looking at https://blog.rust-lang.org/2019/02/28/Rust-1.33.0.html I noticed something interesting, “irrefutable destructuring patterns.” It occurred to me that I’ve had plenty of code where this would be useful.

case class Row(a: A, b: B)

def f(Row(a, b)) ...

def g((a, b): (Int, String)) ...
or maybe
def g((a: Int, b: String)) ...

vs

case class Row(a: A, b: B)

def f(r: Row) ... {
   val Row(a, b) = r
}

def g(tuple: (Int, String)) ... {
  val (a, b) = tuple
}

Something similar I’ve seen proposed (and maybe is in Scala 2.13, not sure) is such patterns in lambdas where we would otherwise have to use case, but this is in the position of method arguments rather than lambdas. It would save a line here and there.


#2

I’ve wanted this many times! Would be a nice addition IMO


#3

Thinking about this some more, it is like the @ part of a pattern match. So you could have

def f(row@Row(a, b))

#4

This is something I would use. Particularly since you can write:

val someFunc = { case ... }
val otherFunc = ((a, b)) =>

and it correctly does the pattern matching.


#5

See: Allow defs to be implemented from functions


#6

I was thinking about how you would find what the type of the argument would be. It’d have to be the left side of the unapply method.

object X0 {
  def unapply(x: Int): Option[Int] = if (x == 0) Some(x) else None
}

def f(X0(zero)): Int = zero

so the type of f would be f(Int): Int, but it could throw a MatchError if one were to call it with f(3). This seems ok because it would throw a MatchError anyway if I were to do val X0(zero) = 5.

What if unapply is overloaded? I suppose in that case you’d have to explicitly state the type.