I am trying to extend String
with a new apply method that lets me apply an higher-order function on it. Example:
case class A(s:String, f: List[String] => List[String])
val f: List[String] => List[String] = { ... stuff ... }
"foo"{f} // == A("foo", f)
So I have defined an implicit conversion from String to something with an apply method that takes a List[String] => List[String]
function.
implicit def c(s:String) = new {
def apply(f: List[String] => List[String]) = A(s, f)
}
But when I try to use it, the conversion collides with the one in Predef that converts String
to StringOps
.
scala> "foo"{f}
<console>:19: error: type mismatch;
found : java.lang.String
required: ?{val apply: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method c in object $iw of type (s: String)java.lang.Object{def apply(f: (List[String]) => List[String]): A}
and method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOps
are possible conversion functions from java.lang.String to ?{val apply: ?}
"foo"{f}
^
Why does it look for a generic apply method (required: ?{val apply: ?}
) and not one that takes an argument of my type (List[String] => List[String]
)?
Edit:
I solved this by refraining from using bare strings to express variables (in the project i'm working on github). So now it looks like this:
case class param(val v: String) {
def apply(f: Emit.Selector) = Variable(v, f)
}
val $foo = param("foo")
foo{selector} // works fine
And I don't need to use implicits.
Further update
It seems scala does look for type parameters in the result types of implicits when searching. I get this to work, but the scenario with the function parameter and the apply method does not work. How come?
scala> class A()
defined class A
scala> class B()
defined class B
scala> implicit def one(s:String) = new {
| def a(a:A) = s + " A"
| }
one: (s: String)java.lang.Object{def a(a: A): java.lang.String}
scala> implicit def another(s:String) = new {
| def a(b:B) = s + " B"
| }
another: (s: String)java.lang.Object{def a(b: B): java.lang.String}
scala> "hello" a new A
res1: java.lang.String = hello A
scala> "hello" a new B
res2: java.lang.String = hello B