Jim McBeath | 5 Oct 21:09

ambiguous implicit conversion error

//Set up two implicit conversions to Option[something]
implicit def optIntToString(n:Option[Int]) = n.get.toString
implicit def optStringToString(s:Option[String]) = s.get.toString

val s1:String = { val opt = Some(123); opt }    //OK, returns "123"
val s2:String = Some(123)       //compiler error, ambiguous implicit conversion

I get this error for the s2 assignment:
    error: type mismatch;
     found   : Some[?A]
     required: String
    Note that implicit conversions are not applicable because they are ambiguous:
     both method optStringToString in object $iw of type (Option[String])java.lang.String
     and method optIntToString in object $iw of type (Option[Int])java.lang.String
     are possible conversion functions from Some[?A] to String
    <console>:6: error: type mismatch;
     found   : Int(123)
     required: String with Int
	   val s2:String = Some(123)

Why is the compiler able to figure out how to convert to s1 but not to s2?
It seems to me that it has the same information available in both cases.
In the error case it says it found Some[?A], why didn't it find Some[Int]?
Is this a bug, or am I missing something about how type inference works?

I tried this in the interpreter using 2.7.1-final and 2.7.2-RC2 with
the same results.

--
Jim
(Continue reading)

Jorge Ortiz | 5 Oct 21:28
Gravatar

Re: ambiguous implicit conversion error

I don't know about your particular error, but using an implicit conversion that calls "get" on an Option defeats the whole point of using Options.

It works fine for Some, but when you have a None the implicit conversion will just throw an exception. This quickly becomes as bad as or worse than NullPointerExceptions.

--j

On Sun, Oct 5, 2008 at 12:11 PM, Jim McBeath <scala <at> j.jimmc.org> wrote:
//Set up two implicit conversions to Option[something]
implicit def optIntToString(n:Option[Int]) = n.get.toString
implicit def optStringToString(s:Option[String]) = s.get.toString

val s1:String = { val opt = Some(123); opt }    //OK, returns "123"
val s2:String = Some(123)       //compiler error, ambiguous implicit conversion

I get this error for the s2 assignment:
   error: type mismatch;
    found   : Some[?A]
    required: String
   Note that implicit conversions are not applicable because they are ambiguous:
    both method optStringToString in object $iw of type (Option[String])java.lang.String
    and method optIntToString in object $iw of type (Option[Int])java.lang.String
    are possible conversion functions from Some[?A] to String
   <console>:6: error: type mismatch;
    found   : Int(123)
    required: String with Int
          val s2:String = Some(123)

Why is the compiler able to figure out how to convert to s1 but not to s2?
It seems to me that it has the same information available in both cases.
In the error case it says it found Some[?A], why didn't it find Some[Int]?
Is this a bug, or am I missing something about how type inference works?

I tried this in the interpreter using 2.7.1-final and 2.7.2-RC2 with
the same results.

--
Jim

Jim McBeath | 5 Oct 22:18

Re: ambiguous implicit conversion error

Jorge,

Yes, I know.  The body of the implicit conversion is irrelevant to
the example, I was trying to cut the code down to the minimum that
would exhibit the issue.

--
Jim

On Sun, Oct 05, 2008 at 12:28:11PM -0700, Jorge Ortiz wrote:
>    I don't know about your particular error, but using an implicit
>    conversion that calls "get" on an Option defeats the whole point of
>    using Options.
>    It works fine for Some, but when you have a None the implicit
>    conversion will just throw an exception. This quickly becomes as bad as
>    or worse than NullPointerExceptions.
>    --j
>    On Sun, Oct 5, 2008 at 12:11 PM, Jim McBeath <scala <at> j.jimmc.org> wrote:
> 
>      //Set up two implicit conversions to Option[something]
>      implicit def optIntToString(n:Option[Int]) = n.get.toString
>      implicit def optStringToString(s:Option[String]) = s.get.toString
>      val s1:String = { val opt = Some(123); opt }    //OK, returns "123"
>      val s2:String = Some(123)       //compiler error, ambiguous implicit
>      conversion
>      I get this error for the s2 assignment:
>         error: type mismatch;
>          found   : Some[?A]
>          required: String
>         Note that implicit conversions are not applicable because they
>      are ambiguous:
>          both method optStringToString in object $iw of type
>      (Option[String])java.lang.String
>          and method optIntToString in object $iw of type
>      (Option[Int])java.lang.String
>          are possible conversion functions from Some[?A] to String
>         <console>:6: error: type mismatch;
>          found   : Int(123)
>          required: String with Int
>                val s2:String = Some(123)
>      Why is the compiler able to figure out how to convert to s1 but not
>      to s2?
>      It seems to me that it has the same information available in both
>      cases.
>      In the error case it says it found Some[?A], why didn't it find
>      Some[Int]?
>      Is this a bug, or am I missing something about how type inference
>      works?
>      I tried this in the interpreter using 2.7.1-final and 2.7.2-RC2 with
>      the same results.
>      --
>      Jim

Paul Phillips | 5 Oct 22:50

Re: ambiguous implicit conversion error

On Sun, Oct 05, 2008 at 01:21:35PM -0700, Jim McBeath wrote:
> Yes, I know.  The body of the implicit conversion is irrelevant to the example, I was trying to cut the code
down to 
> the minimum that would exhibit the issue.

The parameter lists for the two implicit methods have the same erasure.  I feel like this is the root of the
problem, 
but I can't explain it satisfactorily because type inference should take place before erasure.  Since the
error 
reports the type of Some(123) as Some[?A] it seems safe it's not Some[Int], which is what it is in the one
which 
works.  Notice it works if we approach the implicit differently:

  scala> val s2 = Some(123) + "b"
  s2: java.lang.String = 123b

If you parameterize the implicit it works as you want:

  scala> implicit def optToString[T](s: Option[T]): String = s.get.toString
  optToString: [T](Option[T])String
  scala> val s2: String = Some(123)
  s2: String = 123

I also wonder about the later message:

> >          found   : Int(123)
> >          required: String with Int

I don't think scala will be seeing that required "String with Int" anytime soon.

--

-- 
Paul Phillips      | One way is to make it so simple that there are
Everyman           | obviously no deficiencies. And the other way is to make
Empiricist         | it so complicated that there are no obvious deficiencies.
i pull his palp!   |     -- Hoare

Jim McBeath | 6 Oct 02:56

Re: ambiguous implicit conversion error

On Sun, Oct 05, 2008 at 01:50:48PM -0700, Paul Phillips wrote:
> On Sun, Oct 05, 2008 at 01:21:35PM -0700, Jim McBeath wrote:
> > Yes, I know.  The body of the implicit conversion is irrelevant to the example, I was trying to cut the code
down to 
> > the minimum that would exhibit the issue.
> 
> The parameter lists for the two implicit methods have the same erasure.  I feel like this is the root of the
problem, 
> but I can't explain it satisfactorily because type inference should take place before erasure.  Since the
error 
> reports the type of Some(123) as Some[?A] it seems safe it's not Some[Int], which is what it is in the one
which 
> works.  Notice it works if we approach the implicit differently:
> 
>   scala> val s2 = Some(123) + "b"
>   s2: java.lang.String = 123b
> 
> If you parameterize the implicit it works as you want:
> 
>   scala> implicit def optToString[T](s: Option[T]): String = s.get.toString
>   optToString: [T](Option[T])String
>   scala> val s2: String = Some(123)
>   s2: String = 123

Based on this suggestion, I tried changing my implicits from this (as
originally posted):

  implicit def optIntToString[Int](n:Option[Int]) = n.get.toString
  implicit def optStringToString[String](s:Option[String]) = s.get.toString

to this:

  implicit def optIntToString[I<:Int](n:Option[I]) = n.get.toString
  implicit def optStringToString[S<:String](s:Option[S]) = s.get.toString

With this slightly modified definition, the assignment that used to fail:

  val s2:String = Some(123)

now works, although the erasures are still identical.

--
Jim

Paul Phillips | 6 Oct 18:26

Re: ambiguous implicit conversion error

On Sun, Oct 05, 2008 at 05:56:11PM -0700, Jim McBeath wrote:
> Based on this suggestion, I tried changing my implicits from this (as
> originally posted):
> 
>   implicit def optIntToString[Int](n:Option[Int]) = n.get.toString
>   implicit def optStringToString[String](s:Option[String]) = s.get.toString

FYI that's not what was originally posted, and those don't do what they might appear to 
do.  The original versions had no type parameters:

  implicit def optIntToString(n:Option[Int]) = n.get.toString
  implicit def optStringToString(s:Option[String]) = s.get.toString

The two methods up top each has a type parameter, the first calling it "Int", the second 
"String", and in reality they're the same method.  I found a while ago that it's wise to 
always explicitly state return types in implicits, and in this case that would have shown 
the error because the type parameter String shadows java.lang.String.

scala> implicit def optStringToString[String](s:Option[String]): String = s.get.toString
<console>:4: error: type mismatch;
 found   : java.lang.String
 required: String
       implicit def optStringToString[String](s:Option[String]): String = s.get.toString

>   implicit def optIntToString[I<:Int](n:Option[I]) = n.get.toString
>   implicit def optStringToString[S<:String](s:Option[S]) = s.get.toString
> 
> With this slightly modified definition, the assignment that used to fail:
> 
>   val s2:String = Some(123)
> 
> now works, although the erasures are still identical.

The method parameter lists still have the same erasure, but now the methods are 
polymorphic with different type bounds.

--

-- 
Paul Phillips      | We must respect the other fellow's religion, but only
Future Perfect     | in the sense and to the extent that we respect his
Empiricist         | theory that his wife is beautiful and his children smart. 
i pull his palp!   |     -- H. L. Mencken

Jim McBeath | 7 Oct 01:20

Re: ambiguous implicit conversion error

On Mon, Oct 06, 2008 at 09:26:49AM -0700, Paul Phillips wrote:
> On Sun, Oct 05, 2008 at 05:56:11PM -0700, Jim McBeath wrote:
> > Based on this suggestion, I tried changing my implicits from this (as
> > originally posted):
> > 
> >   implicit def optIntToString[Int](n:Option[Int]) = n.get.toString
> >   implicit def optStringToString[String](s:Option[String]) = s.get.toString
> 
> FYI that's not what was originally posted, and those don't do what they might appear to 
> do.  The original versions had no type parameters:
> 
>   implicit def optIntToString(n:Option[Int]) = n.get.toString
>   implicit def optStringToString(s:Option[String]) = s.get.toString
> 
> The two methods up top each has a type parameter, the first calling it "Int", the second 
> "String", and in reality they're the same method.  I found a while ago that it's wise to 
> always explicitly state return types in implicits, and in this case that would have shown 
> the error because the type parameter String shadows java.lang.String.
> 
> scala> implicit def optStringToString[String](s:Option[String]): String = s.get.toString
> <console>:4: error: type mismatch;
>  found   : java.lang.String
>  required: String
>        implicit def optStringToString[String](s:Option[String]): String = s.get.toString

Mea culpa.  I usually run what I post through the interpreter first
to make sure I am posting the right code, but this time I took
a short cut and just typed it in (incorrectly, as you point out)
rather than pasting what I ran through the interpreter.  One more
experience to support the practice of full unit testing.

> >   implicit def optIntToString[I<:Int](n:Option[I]) = n.get.toString
> >   implicit def optStringToString[S<:String](s:Option[S]) = s.get.toString
> > 
> > With this slightly modified definition, the assignment that used to fail:
> > 
> >   val s2:String = Some(123)
> > 
> > now works, although the erasures are still identical.
> 
> The method parameter lists still have the same erasure, but now the methods are 
> polymorphic with different type bounds.

In this case both Int and String are final classes, so I think
specifying [I<:Int] should be the same as requiring an Int as in
the first approach.  I think the approach should work even for
non-final classes, since the type parameter to Option is covariant,
but I haven't tried it, so there may be some issue I am not aware
of - or I may be getting my co and contra confused.

I thought it was interesting that the first approach led to compiler
error messages and the second did not, so the error is apparently
not due solely to type erasure.

--
Jim

> -- 
> Paul Phillips      | We must respect the other fellow's religion, but only
> Future Perfect     | in the sense and to the extent that we respect his
> Empiricist         | theory that his wife is beautiful and his children smart. 
> i pull his palp!   |     -- H. L. Mencken

David MacIver | 5 Oct 22:31

Re: ambiguous implicit conversion error

On Sun, Oct 5, 2008 at 8:11 PM, Jim McBeath <scala <at> j.jimmc.org> wrote:
> //Set up two implicit conversions to Option[something]
> implicit def optIntToString(n:Option[Int]) = n.get.toString
> implicit def optStringToString(s:Option[String]) = s.get.toString
>
> val s1:String = { val opt = Some(123); opt }    //OK, returns "123"
> val s2:String = Some(123)       //compiler error, ambiguous implicit conversion
>
> I get this error for the s2 assignment:
>    error: type mismatch;
>     found   : Some[?A]
>     required: String
>    Note that implicit conversions are not applicable because they are ambiguous:
>     both method optStringToString in object $iw of type (Option[String])java.lang.String
>     and method optIntToString in object $iw of type (Option[Int])java.lang.String
>     are possible conversion functions from Some[?A] to String
>    <console>:6: error: type mismatch;
>     found   : Int(123)
>     required: String with Int
>           val s2:String = Some(123)
>
> Why is the compiler able to figure out how to convert to s1 but not to s2?
>
> It seems to me that it has the same information available in both cases.
> In the error case it says it found Some[?A], why didn't it find Some[Int]?
> Is this a bug, or am I missing something about how type inference works?

If you add a type parameter to Some then it works. i.e. val s2 :
String = Some[Int](123) so I think what's happening here is that it's
seeing that you have an Option[T], determining that this isn't a
String and immediately trying to force an implicit conversion before
attempting to resolve the type parameter of Option and discovering
that it doesn't have enough information at that point.

It looks like a bug to me, but I suspect it might be a difficult one
to resolve (just guessing. I know very little about the type
inferencer). Still worth filing.

Rickard Nilsson | 5 Oct 23:48

Re: ambiguous implicit conversion error

On Sun, 05 Oct 2008 22:31:11 +0200, David MacIver  
<david.maciver <at> gmail.com> wrote:

> On Sun, Oct 5, 2008 at 8:11 PM, Jim McBeath <scala <at> j.jimmc.org> wrote:
>> //Set up two implicit conversions to Option[something]
>> implicit def optIntToString(n:Option[Int]) = n.get.toString
>> implicit def optStringToString(s:Option[String]) = s.get.toString
>>
>> val s1:String = { val opt = Some(123); opt }    //OK, returns "123"
>> val s2:String = Some(123)       //compiler error, ambiguous implicit  
>> conversion
>>
>> I get this error for the s2 assignment:
>>    error: type mismatch;
>>     found   : Some[?A]
>>     required: String
>>    Note that implicit conversions are not applicable because they are  
>> ambiguous:
>>     both method optStringToString in object $iw of type  
>> (Option[String])java.lang.String
>>     and method optIntToString in object $iw of type  
>> (Option[Int])java.lang.String
>>     are possible conversion functions from Some[?A] to String
>>    <console>:6: error: type mismatch;
>>     found   : Int(123)
>>     required: String with Int
>>           val s2:String = Some(123)
>>
>> Why is the compiler able to figure out how to convert to s1 but not to  
>> s2?
>>
>> It seems to me that it has the same information available in both cases.
>> In the error case it says it found Some[?A], why didn't it find  
>> Some[Int]?
>> Is this a bug, or am I missing something about how type inference works?
>
> If you add a type parameter to Some then it works. i.e. val s2 :
> String = Some[Int](123) so I think what's happening here is that it's
> seeing that you have an Option[T], determining that this isn't a
> String and immediately trying to force an implicit conversion before
> attempting to resolve the type parameter of Option and discovering
> that it doesn't have enough information at that point.
>
> It looks like a bug to me, but I suspect it might be a difficult one
> to resolve (just guessing. I know very little about the type
> inferencer). Still worth filing.

There seems to be some issues with implicits and higher-ordered types
used together. I while ago, I reported
http://lampsvn.epfl.ch/trac/scala/ticket/298, which still isn't solved.
The issues are not identical, but they're probably related.

   / Rickard


Gmane