I have an example that compile well up to 2.13.3, but result with a warning " match may not be exhaustive" in 2.13.4
class Node(id: String) {
val isEmpty = false
def get = id
}
object Node {
def apply(id: String) = new Node(id)
def unapply(node: Node) = node
}
val Alice = Node("Alice")
val Node(alice) = Alice
I understand that a solution can bu to redefine “unapply”
def unapply(node: Node) = Some(node.get)
But there is no more use of “name-based pattern matching”.
Do you have any proposal for another solution?
Not sure what you mean with this.
I am also actually surprised that this works:
def unapply(node: Node) = node
AFAIK, a custom extractor needs to return an Option.
Also, I do not set the purpose of that custom extractor, why returning the same node again?
Finally, public methods without explicit return type are a code smell. BTW, any reason for not using a case class?
Does this help?
val isEmpty: false = false
Looks like that doesn’t work (yet).
However you can add @unchecked
.
val Node(alice) = Alice : @unchecked
For me it also goes away if I disable strict-unsealed-patmat
even though this doesn’t seem related to sealed
.
scalacOptions += "-Xlint:_,-strict-unsealed-patmat"
The def unapply(node: Node) = node
is possible, thanks to the “isEmpty” and “get” attributes.
Thanks, but already tried without success.
After 5 years using Scala TIL that you could return something that was not an Option
or a Boolean
in a custom extractor; interesting but, I would certainly not use it.
Do you expect someone to inherit that Node
and override those get
and isEmpty
methods? Because if not, and if they are always constants then I would just.
final class Node(id: String)
object Node {
def apply(id: String): Node = new Node(id)
def unapply(node: Node): Some[String] = Some(node.id)
}
I think one of the use cases is that you could write an extractor/matcher that doesn’t box.
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Even(val get: Int) extends AnyVal {
def isEmpty = get % 2 != 0
}
object Even {
def unapply(i: Int) = new Even(i)
}
// Exiting paste mode, now interpreting.
scala> 3 match { case Even(i) => println(s"$i is even") }
scala.MatchError: 3 (of class java.lang.Integer)
... 40 elided
scala> 2 match { case Even(i) => println(s"$i is even") }
2 is even
Note that this avoids 2 levels of boxing compared to Option[Int]
.