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
Related
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'd like to define a function that applies * 2 to its argument, that works for all types where it's meaningful. I tried using structural types:
import scala.language.reflectiveCalls
def double[T](x: Any{def * (arg0: Int): T}) = x * 2
It works for strings:
scala> double("a")
res85: String = aa
But not for numbers:
scala> double(4)
java.lang.NoSuchMethodException: java.lang.Integer.$times(int)
at java.lang.Class.getMethod(Class.java:1778)
at .reflMethod$Method1(<console>:18)
at .double(<console>:18)
... 32 elided
Why do I get this error message?
Is it possible to do what I want using structural types?
Is it possible to do it in some other way?
Edit: By "do what I want" I mean working for already existing types, such as numbers and strings, not just for classes that I define myself.
* is translated to $times, structural type checks existence of * method, but (I suppose that's a bug) calls it's internal ($times) representations). That works for String, because there is $times for them.
This approach should work for methods with names that only contain letters.
```
import scala.language.reflectiveCalls
def double[T](x: Any{def test (arg0: Int): T}) = x.test(2)
class A { def test(i: Int) = i * 10 }
class B { def test(i: Int) = i * 20 }
scala> double(new A)
res0: Int = 20
scala> double(new B)
res1: Int = 40
Yes, idiomatic answer is typeclasses. You choose what exactly "meaningfulness" is. And they can be applied to any already existing class:
```
trait Multiply[A]{
def times(a: A, x: Int): A
}
implicit val MultString = new Multiply[String] { def times(a: String, x: Int) = a * x }
implicit val MultInt = new Multiply[Int] { def times(a: Int, x: Int) = a * x }
def double[T](t: T)(implicit mult: Multiply[T]) = mult.times(t, 2)
scala> double("aaaa")
res0: String = aaaaaaaa
scala> double(111)
res1: Int = 222
Also note that structural typing uses reflection => is quite slow.
You could always just overload the method. To make it work in the REPL you have to :paste it in as a block.
def double(s:String):String = s * 2
def double[N](n:N)(implicit ev: Numeric[N]):N = {
import Numeric.Implicits._
n * ev.fromInt(2)
}
double("this") // result: String = thisthis
double(3L) // result: Long = 6
One more possibility I've found is to use macros. As of Scala 2.11.8 they are still experimental and, according to Martin Odersky, won't survive in this form. The current synax is clumsy, but so far it is the only method that is completely DRY (* 2 is written only once, and the function works on all types that support this operation).
Regardless of whether this is the best solution, I'm posting it for the sake of completeness:
import reflect.macros.Context
def doubleImpl[T](c: Context)(x: c.Expr[T]): c.Expr[T] = {
import c.universe._
c.Expr(q"${x.tree} * 2")
}
def double[T](x: T): T = macro doubleImpl[T]
I want to create a function g that takes a function f as a parameter, where f has a type parameter. I can't get a signature for g that compiles. One attempt is like this:
scala> def mock1[A](): A = null.asInstanceOf[A] // STUB
mock1: [A]()A
scala> def mock2[A](): A = null.asInstanceOf[A] // STUB
mock2: [A]()A
scala> def g0(f: [A]() => A): Int = f[Int]()
<console>:1: error: identifier expected but '[' found.
def g0(f: [A]() => A): Int = f[Int]()
^
I can get it to work if I wrap the function that takes a type parameter in a trait, like so:
scala> trait FWrapper { def f[A](): A }
defined trait FWrapper
scala> class mock1wrapper extends FWrapper { def f[A]() = mock1[A]() }
defined class mock1wrapper
scala> class mock2wrapper extends FWrapper { def f[A]() = mock2[A]() }
defined class mock2wrapper
scala> def g(wrapper: FWrapper): Int = wrapper.f[Int]()
g: (wrapper: FWrapper)Int
scala> g(new mock1wrapper)
res8: Int = 0
Is there a way I can accomplish this without introducing the wrapper class?
Scala does (currently) not have support for polymorphic function values. You have two options:
Stick with your wrapper trait (probably easiest to understand)
Use polymorphic function values from Shapeless (fancy, but maybe a bit complicated)
How about this:
def mock[A](): A = null.asInstanceOf[A]
def g[A](f:() => A): A = f()
g(mock[Int])
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(_))
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.