Reputation: 4669
I have two implicit conversions that add an apply
method.
implicit def f1(foo: Foo) = new {
def apply(x: Int) = ???
}
implicit def f2(foo: Foo) = new {
def apply(x: Int, y: Int) = ???
}
But I can't use them, because the compiler complains about ambiguous implicit conversions
foo(1) // compile error
Why does it complain if it is clear which one should be used?
Upvotes: 0
Views: 162
Reputation: 4249
If the problem lies in existing implicit inside Predef
, you should disable Predef
import like described here: Override Predef's implicit conversions
By example, let's try to make new apply
function for String
.
scala> implicit def stringToFunction(s: String) = new {
| def apply(x1: Int) = ???
| }
stringToFunction: (s: String)AnyRef{def apply(x1: Int): Nothing}
scala> "123"(15)
<console>:13: error: type mismatch;
found : String("123")
required: ?{def apply: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOps
and method stringToFunction of type (s: String)AnyRef{def apply(x1: Int): Nothing}
are possible conversion functions from String("123") to ?{def apply: ?}
"123"(15)
^
<console>:13: error: String("123") does not take parameters
"123"(15)
^
So, we should disable augmentString
import from Predef
:
scala> import Predef.{augmentString => _, _}
import Predef.{augmentString=>_, _}
scala> "123"(15)
<console>:14: error: type mismatch;
found : String("123")
required: ?{def apply: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method wrapString in class LowPriorityImplicits of type (s: String)scala.collection.immutable.WrappedString
and method stringToFunction of type (s: String)AnyRef{def apply(x1: Int): Nothing}
are possible conversion functions from String("123") to ?{def apply: ?}
"123"(15)
^
<console>:14: error: String("123") does not take parameters
"123"(15)
^
Let's disable wrapString
too, that will finally achieve what we wanted to do:
scala> import Predef.{augmentString => _, wrapString => _, _}
import Predef.{augmentString=>_, wrapString=>_, _}
scala> "123"(15)
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:284)
at $anon$1.apply(<console>:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
... 31 elided
You can do the same for implicit conversions from your class Foo
, following compiler complaints about ambigious conversions.
Upvotes: 1
Reputation: 4249
You should include both apply()
's into one implicit:
implicit def f1(foo: Foo) = new {
def apply(x: Int) = ???
def apply(x: Int, y: Int) = ???
}
From http://docs.scala-lang.org/tutorials/tour/implicit-conversions:
An implicit conversion from type S to type T is defined by an implicit value which has function type S => T, or by an implicit method convertible to a value of that type.
So, you should have exactly one implicit method converting Foo
to function.
How it works in your example case:
foo(1)
invocation.foo.apply(1)
.Foo
doesn't have method apply
and tries to find implicit conversion to class with this method.f1
and f2
, and gives up on it.Upvotes: 3