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.
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.
In Common Lisp this is called argument-destructuring. It seems to me that having automatically destructuring function arguments could only be a positive improvement. It would help programmers write less repetitive code, and this pattern occurs often. It is indeed a nice feature of the closure language as I understand (not being a cloJure expert). It is also a feature of Common Lisp, but unfortunately in CL the feature is only available to macros, not to normal lambda functions (but as most things it can be added to CL lambda functions using macros).
This seems pretty cool, however I think if patterns are to be promoted to def args, I would strongly suggest that only patterns that can be checked for exhaustion should be allowed - its quite clear that you opt-in to unsafety with patt-defs.
Destructuring of structs in Rust is irrefutable because there’s no way to override the default destructuring semantics i.e. there’s no equivalent of CompanionObject.unapply. Rust’s destructuring relies exclusively on struct fields. Scala relies exclusively on unapply method and because this method is opaque to the compiler, no destructuring is irrefutable (unless we’re talking about types from standard library which could be assumed to be unchanging).
Even though in Scala the situation is messier than Rust, we could still benefit from the idea, and code using it would be no more unsafe than it already is.