Avoiding implicit def ambiguity in Scala

后端 未结 6 1317
悲哀的现实
悲哀的现实 2021-01-07 23:27

I am trying to create an implicit conversion from any type (say, Int) to a String...

An implicit conversion to String means RichString methods (like reverse) are not

相关标签:
6条回答
  • 2021-01-07 23:58

    I'm confused: can't you use .toString on any type anyway thus avoiding the need for implicit conversions?

    0 讨论(0)
  • 2021-01-08 00:00

    Either make a huge proxy class, or suck it up and require the client to disambiguate it:

    100.asInstanceOf[String].length

    0 讨论(0)
  • 2021-01-08 00:03

    I don't have a solution, but will comment that the reason RichString methods are not available after your intToString implicit is that Scala does not chain implicit calls (see 21.2 "Rules for implicits" in Programming in Scala).

    If you introduce an intermediate String, Scala will make the implict converstion to a RichString (that implicit is defined in Predef.scala).

    E.g.,

    $ scala
    Welcome to Scala version 2.7.5.final [...].
    Type in expressions to have them evaluated.
    Type :help for more information.
    
    scala> implicit def intToString(i: Int) = String.valueOf(i)
    intToString: (Int)java.lang.String
    
    scala> val i = 100
    i: Int = 100
    
    scala> val s: String = i
    s: String = 100
    
    scala> s.reverse
    res1: scala.runtime.RichString = 001
    
    0 讨论(0)
  • 2021-01-08 00:07

    As of Scala 2.8, this has been improved. As per this paper (§ Avoiding Ambiguities) :

    Previously, the most specific overloaded method or implicit conversion would be chosen based solely on the method’s argument types. There was an additional clause which said that the most specific method could not be defined in a proper superclass of any of the other alternatives. This scheme has been replaced in Scala 2.8 by the following, more liberal one: When comparing two different applicable alternatives of an overloaded method or of an implicit, each method gets one point for having more specific arguments, and another point for being defined in a proper subclass. An alternative “wins” over another if it gets a greater number of points in these two comparisons. This means in particular that if alternatives have identical argument types, the one which is defined in a subclass wins.

    See that other paper (§6.5) for an example.

    0 讨论(0)
  • 2021-01-08 00:08

    The only option I see is to create a new String Wrapper class MyString and let that call whatever method you want to be called in the ambiguous case. Then you could define implicit conversions to MyString and two implicit conversions from MyString to String and RichString, just in case you need to pass it to a library function.

    0 讨论(0)
  • 2021-01-08 00:12

    The accepted solution (posted by Mitch Blevins) will never work: downcasting Int to String using asInstanceOf will always fail.

    One solution to your problem is to add a conversion from any String-convertible type to RichString (or rather, to StringOps as it is now named):

    implicit def stringLikeToRichString[T](x: T)(implicit conv: T => String) = new collection.immutable.StringOps(conv(x))
    

    Then define your conversion(s) to string as before:

    scala> implicit def intToString(i: Int) = String.valueOf(i)
    warning: there was one feature warning; re-run with -feature for details
    intToString: (i: Int)String
    
    scala> 100.toCharArray
    res0: Array[Char] = Array(1, 0, 0)
    
    scala> 100.reverse
    res1: String = 001
    
    scala> 100.length
    res2: Int = 3
    
    0 讨论(0)
提交回复
热议问题