Implicit parameters won't work on unapply. How to hide ubiquitous parameters from extractors?

Apparently unapply/unapplySeq in extractor objects do not support implicit parameters. Assuming here an interesting parameter a, and a disturbingly ubiquitous parameter b that would be nice to hide away, when extracting c.

[EDIT]: It appears something was broken in my intellij/scala-plugin installation that caused this. I cannot explain. I was having numerous strange problems with my intellij lately. After reinstalling, I can no longer reprodce my problem. Confirmed that unapply/unapplySeq do allow for implicit parameters! Thanks for your help.

This does not work (*EDIT:yes, it does):*

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 like, in which the intention is intuitively clear also to Java folks, this limitation basically forbids extractor objects which depend on additional parameter(s).

How do you typically handle this limitation?

So far I've got those four possible solutions:

1) The simplest solution that I want to improve on: don't hide b, provide parameter b along with a, as normal parameter of unapply in 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 it because there is more noise deviating that deconstruction of a into c is important here. Also since java folks, that have to be convinced to actually use this scala code, are confronted with one additional synthactic novelty (the tuple braces). They might get anti-scala aggressions "What's all this? ... Why then not use a normal method in the first place and check with if?".

2) define extractors within a class encapsulating the dependence on a particular B, import extractors of that instance. At import site a bit unusual for java folks, but at pattern match site b is hidden nicely and it is intuitively evident what happens. My favorite. Some disadvantage I missed?

class BDependent(b:B){ 
   object A2{ 
    def unapply(a:A):Option[C] = Option(b.getC(a))
         } }

usage 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 scope of client code. b is hidden, since it can use a "b" in local scope. Hampers code reuse, heavily pollutes client code (additionally, it has to be stated before code using it).

4) have unapply return Option of function B => C. This allows import and usage of an ubitious-parameter-dependent extractor, without providing b directly to the extractor, but instead to the result when used. Java folks maybe confused by usage of function values, b 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 remarks:

  • As suggested in this answer, "view bounds" may help to get extractors work with implicit conversions, but this doesn't help with implicit parameters. For some reason I prefer not to workaround with implicit conversions.
  • looked into "context bounds", but they seem to have the same limitation, don't they?

Answers


In what sense does your first line of code not work? There's certainly no arbitrary prohibition on implicit parameter lists for extractor methods.

Consider the following setup (I'm using plain old classes instead of case classes to show that there's no extra magic happening here):

class A(val i: Int)
class C(val x: String)
class B(pre: String) { def getC(a: A) = new C(pre + a.i.toString) }

Now we define an implicit B value and create an extractor object with your unapply method:

implicit val b = new B("prefix: ")

object D {
  def unapply(a: A)(implicit b: B): Option[C] = Option(b getC a)
}

Which we can use like this:

scala> val D(c) = new A(42)
c: C = C@52394fb3

scala> c.x
res0: String = prefix: 42

Exactly as we'd expect. I don't see why you need a workaround here.


Need Your Help

How to merge XML objects with jQuery / JavaScript

javascript jquery xml xml-parsing merge

I want to merge data of different XML files into one big XML tree. My idea is to append all upcoming nodes to the root node of the first XML file. However, I get a "TypeError" when trying to call

Using this and super in Java

java inheritance this super

I have the following code snippet that attempts to use this and super.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.