Is there something I've got wrong with the following fragment:-
object Imp {
implicit def string2Int(s: String): Int = s.toInt
def f(i: Int) = i
def main(args: Array[String]) {
val n: Int = f("666")
}
}
I get the following from the 2.8 compiler:-
Information:Compilation completed with 1 error and 0 warnings
Information:1 error
Information:0 warnings
...\scala-2.8-tests\src\Imp.scala
Error:Error:line (4)error: type mismatch;
found : String
required: ?{val toInt: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method string2Int in object Imp of type (s: String)Int
and method augmentString in object Predef of type (x:String)scala.collection.immutable.StringOps
are possible conversion functions from String to ?{val toInt: ?}
implicit def string2Int(s: String): Int = s.toInt
What is happening is that Java does not define a toInt method on String. In Scala, what defines that method is the class StringOps (Scala 2.8) or RichString (Scala 2.7).
On the other hand, there is a method toInt available on Int as well (through another implicit, perhaps?), so the compiler doesn't know if it is to convert the string to StringOps, through the defined implicit, or to Int, through your own implicit.
To solve it, call the implicit explicitly.
object Imp {
implicit def string2Int(s: String): Int = augmentString(s).toInt
def f(i: Int) = i
def main(args: Array[String]) {
val n: Int = f("666")
}
}
There is already an implicit conversion in scope, from scala.Predef. You don't need to declare your own implicit conversion to add a toInt method to a String. You have 3 options (I'd go for the last one!):
Change your method name to something like asInt
Unimport the conversion in Predef
Don't bother defining your own and use instead the toInt that comes bundled with the scala library
Note that scala will only make use of an in-scope implicit conversion if it is unique.
I think I have a workaround.
If I create a RichString from the String argument, the implicit conversion occurs from RichString to Int using the implicit method I provide (this works for 2.7.x and 2.8). If I remove my implicit I get a type error.
object Imp {
implicit def string2Int(rs: RichString): Int = rs.toInt
def f(i: Int) = i
def main(args: Array[String]) {
val n: Int = f(new RichString("666"))
println(n)
}
}
I'm still confused as to why both implicits came into scope and clashed when I provided an implicit and as to why the Predef one didn't come into scope when I didn't provide one for String to Int. I suppose the question about an implicit conversion from String to Int remains open.
Related
I am new to Scala, and trying to get my head around implicit wizardry. I want to understand why I am getting 2mysize with + function and the 2 * the length for * function?
implicit def addToStr(str: String) = str.size
scala> 2 * "mysize"
res4: Int = 12
scala> 2 + "mysize"
res3: String = 2mysize
Have a look at the ScalaDocs page for the Int API. The Int class has a +() method for adding a String.
abstract def +(x: String): String
But it has no *() method for multiplying a String. The compiler will always choose a defined function/method over an implicit. It will only go looking for an implicit solution as a last resort.
Implicit Conversions are only applied if the expression doesn't match the argument type of the function.
Example:
import scala.language.implicitConversions
implicit def strToInt(s: String):Int = s.size
def printStr(s: Int):Unit = {
println(s"Printing Int ${s}")
}
printStr("SSSS")
In the above case, the implicit method comes into picture, but if you define another method as shown below.
def printStr(s: String) = {
println(s"Printing String ${s}")
}
It will automatically use this method rather than implicit resolutions.
https://www.scala-lang.org/old/node/3911.html
Using the Scala REPL, I've defined a function that takes an Int as its first parameter and a function with this signature Int => Int as the second implicit parameter:
scala> def doer(i: Int)(implicit a: Int => Int): Int = a(i)
doer: (i: Int)(implicit a: Int => Int)Int
Why does running this function without providing the implicit parameter work?
scala> doer(4)
res1: Int = 4
Where does the implicit Int to Int function come from?
The REPL reports that there are no implicits defined:
scala> :impl
No implicits have been imported other than those in Predef.
Predef contains an implicit evidence that one type is a subtype of another: A <:< B. Every type is a subtype of itself so implicitly[Int <:< Int] works. This <:< class extends function A => B. So that's why implicitly[Int => Int] also works.
Int and java.lang.Integer however are different things with no subtype relation whatsoever, so these int2Integer implicits have nothing to do with it.
If you have a REPL of a recent Scala version you can type
scala> doer(4) //print
And press the tab key instead of enter. It will show you the desugared version doer(4)(scala.Predef.$conforms[Int]) of your code with all implicits filled in explicitly.
There are bunch of implicits defined in scala.Predef which are accessible in all Scala compilation units without explicit qualification, and one of them is
implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Integer]
If you check the Predef source code it is possible to see a lot of implicit functions. The compiler will just pick up a compatible one.
Some examples:
implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs)
implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte] = new ArrayOps.ofByte(xs)
implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char] = new ArrayOps.ofChar(xs)
implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double] = new ArrayOps.ofDouble(xs)
implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float] = new ArrayOps.ofFloat(xs)
implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int] = new ArrayOps.ofInt(xs)
implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long] = new ArrayOps.ofLong(xs)
implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps.ofRef[T](xs)
implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short] = new ArrayOps.ofShort(xs)
implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit] = new ArrayOps.ofUnit(xs)
// "Autoboxing" and "Autounboxing" ---------------------------------------------------
implicit def byte2Byte(x: Byte) = java.lang.Byte.valueOf(x)
implicit def short2Short(x: Short) = java.lang.Short.valueOf(x)
implicit def char2Character(x: Char) = java.lang.Character.valueOf(x)
implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x)
implicit def long2Long(x: Long) = java.lang.Long.valueOf(x)
implicit def float2Float(x: Float) = java.lang.Float.valueOf(x)
implicit def double2Double(x: Double) = java.lang.Double.valueOf(x)
implicit def boolean2Boolean(x: Boolean) = java.lang.Boolean.valueOf(x)
implicit def Byte2byte(x: java.lang.Byte): Byte = x.byteValue
implicit def Short2short(x: java.lang.Short): Short = x.shortValue
implicit def Character2char(x: java.lang.Character): Char = x.charValue
implicit def Integer2int(x: java.lang.Integer): Int = x.intValue
implicit def Long2long(x: java.lang.Long): Long = x.longValue
implicit def Float2float(x: java.lang.Float): Float = x.floatValue
implicit def Double2double(x: java.lang.Double): Double = x.doubleValue
implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue
Implicits are designed for such purpose. The compiler will search if any implicit definition objects are available. If it finds then will use them. There are many implicit definition objects provided scala. You can also define the custom objects to be implicit and will be used if they are within the scope of your code.
See the doc
https://docs.scala-lang.org/tour/implicit-parameters.html
doer works because since it accepts implicit parameter, it is available in Predef. Predef is imported automatically to scala scope. Looks like the function used is int2Integer.
I want to have 2 implicit comvertors in scala
To convert string to int
To convert int to float
implicit def String2Int(v: String): Int = Integer.parseInt(v)
The above works but when I write below
implicit def String2Float(v: String): Float = v.toFloat
It gives compile error cannot resolve symbol to Float
Can we not have 2 implicit converters in one file?
In scala, String does not have toInt, toFloat, etc methods. Where are they taken from?
Scala has Predef object which is imported implicitly in every source (even if you are not importing it).
Predef has the following method:
#inline implicit def augmentString(x: String): StringOps = new StringOps(x)
So it implicitly converts any value of type String to StringOps.
StringOps defines methods:
def toInt: Int = java.lang.Integer.parseInt(toString)
def toFloat: Float = java.lang.Float.parseFloat(toString)
...
So when you write str.toFloat - the compiler actually converts String to StringOps and calls the appropriate method.
Ok. What is the problem with your code?
implicit def String2Float(v: String): Float = v.toFloat
Compiler tries to find something that has .toFloat, it finds it in StringOps and in Float via String2Float method. (Float also has toFloat method).
Compiler "didn't add" the method toFloat (of Predef) to String because it cannot decide which implicit conversion to apply and implicit conversion from String to StringOps is broken.
So String does not have toFoat method anymore and that's why you have error (cannot resolve symbol to Float )
(Actually, you should have 2 errors:
Note that implicit conversions are not applicable because they are ambiguous: ... AND value toFloat is not a member of String)
Solution is to use
implicit def String2Float(v: String): Float = java.lang.Float.parseFloat(v)
Like you did in Int case.
Now it converts String to Float directly, without implicit conversions (like it was in v.toFloat case)
P.S. Thank #Dima for pointing to mistake in my answer.
You can define String2Float as:
implicit def String2Float(v: String): Float = {
val i:Int = v
i.toFloat
}
or pass implicit converter as:
implicit def String2Float(v: String)(implicit f: String => Int): Float = {
v.toFloat
}
or get the converter instance implicitly:
implicit def String2Float(v: String): Float = {
val f = implicitly[String => Int]
f(v).toFloat
}
In this case compiler resolves everything successfully
I'm having issues trying to map some methods defined with implicit arguments over an Option type.
Let's say I define a custom class and a trait with the aforementioned methods operating on said class
class MyClass
trait Processor {
def stringy(implicit arg: MyClass) = arg.toString
def lengthy(implicit arg: MyClass) = arg.toString.length
def inty(implicit arg: MyClass) = arg.toString.map(_.toInt).sum
}
Then I create an implementation with some tests
object TestProcessing extends Processor {
//Here everything works fine, the argument is passed explicitly
def test() {
val my = new MyClass
val res = List(stringy(my), lengthy(my), inty(my))
println(res.mkString("\n"))
}
//Still everything ok, the argument is passed implicitly
def testImplicit() {
implicit val my = new MyClass
val res = List(stringy, lengthy, inty)
println(res.mkString("\n"))
}
object Mapper {
//class wrapped in an Option
val optional = Some(new MyClass)
//trying to factor out common code
def optionally[T](processFunction: MyClass => T): Option[T] = optional map processFunction
//now the specific processing methods that should work on the optional value
def s: Option[String] = optionally(stringy)
def l: Option[Int] = optionally(lengthy)
def i: Option[Int] = optionally(inty)
/*
* Here the compiler complains that
*
*<console>:40: error: could not find implicit value for parameter arg: MyClass
* def s: Option[String] = optionally(stringy)
* ^
*<console>:41: error: could not find implicit value for parameter arg: MyClass
* def l: Option[Int] = optionally(lengthy)
* ^
*<console>:42: error: could not find implicit value for parameter arg: MyClass
* def i: Option[Int] = optionally(inty)
* ^
*/
}
}
While optionally is conceived to explicitly pass the optional value explicitly to its argument function, the compiler demands an implicit definition when I use it on the actual functions.
I have two possible solutions, neither of which is satisfactiory:
passing an implicit argument to optionally as in
optionally(implicit my => stringy)
avoid defining the argument to the specific functions as implicit, as in
def stringy(arg: MyClass)
Each solution defies the goal of achieving both readability and usability.
Is there a third way to go?
If I understand correctly, the problem is that the compiler doesn't seem recognize that you want to partially apply / lift the method to a function here (instead it "thinks" you want to leave out the implicit parameter), so doing that explicitly seems to work:
def s: Option[String] = optionally(stringy(_))
def l: Option[Int] = optionally(lengthy(_))
def i: Option[Int] = optionally(inty(_))
Here is a code snippet that tries to reproduce a problem I am facing while implementing an internal DSL:
object testObj {
implicit def foo1[T <% Function1[Int, Int]](fun: T): String = "foo1"
implicit def foo2[T <% Function2[Int, Int, Int]](fun: T): String = "foo2"
def test(arg: String): Unit = {}
test((x:Int) => 5) //Ambiguous implicit conversion error
test((x:Int, y:Int) => 5) //Ambiguous implicit conversion error
}
I am getting ambiguous implicit conversions errors at the shown locations:
<console>:21: error: type mismatch;
found : Int => Int
required: String
Note that implicit conversions are not applicable because they are ambiguous:
both method foo1 in object testObj of type [T](fun: T)(implicit evidence$1: T => (Int => Int))String
and method foo2 in object testObj of type [T](fun: T)(implicit evidence$2: T => ((Int, Int) => Int))String
are possible conversion functions from Int => Int to String
test((x:Int) => 5) //Ambiguous implicit conversion error
^
However commenting one of the implicits does not solve the problem. I am using view bounds since finally I want to chain the implicits. Note that the code snippet given above does not involve implicit chaining.
I was expecting that foo1 implicit conversion would be applicable for the first test application whereas foo2 implicit conversion would be applicable for the second test application.
I don't understand how both the implicits are applicable to both the testfunction applications. Why is this happening and how to make this work?
Edit:
If I don't use view bounds, it works fine as shown below. But I want to use view bounds since I want to chain the implicits the way it is explained in the post How can I chain implicits in Scala?.
implicit def foo1(fun: Function1[Int, Int]): String = "foo1"
implicit def foo2(fun: Function2[Int, Int, Int]): String = "foo2"
def test(arg: String): Unit = {}
test((x:Int) => 5) //No error
test((x:Int, y:Int) => 5) //No error
I'm afraid this won't work. View bounds are just not taken into account when resolving implicits and thus you can't chain implicits. That is be design, because such chaining could create some very unreadable code. The only option I see is to create a new implicit conversion for each possible chain of conversions.