Apparently, unapply / unapplySeq in extractor objects does not support implicit parameters. Assuming here an interesting parameter a and an alarmingly ubiquitous parameter b, which would be nice to hide when extracting c.
[ EDIT ]: It seems that something was broken in my intellij / scala-plugin installation that caused this. I can not explain. I have had a lot of strange problems lately. After reinstalling, I can no longer repurpose my problem. Confirmed that unapply / unapplySeq allow you to use implicit parameters! Thank you for your help.
This does not work (** EDIT : yes, it is): **
trait A; trait C; trait B { def getC(a: A): C } def unapply(a:A)(implicit b:B):Option[C] = Option(b.getC(a))
In my understanding of what an ideal extractor should be, in which the intention is intuitive for Java people, this restriction basically prohibits extract objects that depend on additional parameters (s).
How do you usually deal with this limitation?
So far I have four possible solutions:
1) The simplest solution I want to improve: do not hide b, specify the parameter b together with a as a normal unapply parameter in the form of a tuple:
object A1{ def unapply(a:(A,B)):Option[C] = Option(a._2.getC(a._1)) }
in client code:
val c1 = (a,b) match { case A1(c) => c1 }
I don't like this because more noise is rejected that deconstructing a to c is important here. Also, since the Java people, who need to be sure that they really use this scala code, are faced with one additional syntax novelty (tuple bindings). They can get anti-scala aggression "What is all this? ... Why then not use the normal method in the first place and check if?".
2) extractors are defined inside the class encapsulating the dependence on a specific B, import extractors of this instance. The import site is a little unusual for java users, but the template matching site b hides well and it is intuitively obvious what is happening. My favorite. What was the flaw I missed?
class BDependent(b:B){ object A2{ def unapply(a:A):Option[C] = Option(b.getC(a)) } }
in client code:
val bDeps = new BDependent(someB) import bDeps.A2 val a:A = ... val c2 = a match { case A2(c) => c } }
3) declare extractor objects in the amount of client code. b is hidden since it can use "b" in the local area. Reuse of Hampers code is very dirty client code (in addition, it must be specified before using the code).
4) have an unapply return Function option B => C. This allows you to import and use a parameter-dependent, parameter-dependent, without providing b directly to the extractor, and instead the result when used. Java users can be confused by using function values, b are not hidden:
object A4{ def unapply[A,C](a:A):Option[B => C] = Option((_:B).getC(a)) }
then in client code:
val b:B = ... val soonAC: B => C = a match { case A4(x) => x } val d = soonAC(b).getD ...
Further comments:
- As suggested in this answer , “view borders” can help get extractors with implicit conversions, but this does not help with implicit parameters. For some reason, I prefer not to do with implicit conversions.
- considered "context boundaries," but they seem to have the same restriction, right?