Could someone give a quick explanation why implicit conversion doesn't work in these cases? Thanks.
scala> implicit def strTwoInt (s: String):Int = s.toCharArray.map{_.asDigit}.sum
strTwoInt: (s: String)Int
scala> List[Int]("1","2","3") sum
res3: Int = 6
scala> List("1","2","3") sum
<console>:9: error: could not find implicit value for parameter num: Numeric[java.lang.String]
List("1","2","3") sum
scala> val a = List("1","2","3")
scala> a.foldLeft(0)((i:Int, j:Int) => i+j)
<console>:10: error: type mismatch;
found : (Int, Int) => Int
required: (Int, java.lang.String) => Int
Your implicit conversion converts a String in an Int. In your first example, it is triggered by the fact that you try to put Strings into a List of Ints.
In your second example, you have a List of String and you call the method sum, which takes an implicit Numeric[String]. Your conversion does not apply because you neither try to pass a String somewhere the compiler was expecting an Int, nor you tried to call a method which is defined in Int and not in String. In that case, you can either define a Numeric[String] which use explicitly your conversion, or use a method which takes a List[Int] as parameter (giving hint to the compiler):
scala> def sumIt( xs: List[Int] ) = xs sum
sumIt: (xs: List[Int])Int
scala> sumIt( List("1","2","3") )
res5: Int = 6
In the third example, the foldLeft second argument must be of type:
(Int,String) => Int
the one you actually passed is of type:
(Int,Int) => Int
however, you did not define any implicit conversion between these two types. But:
a.foldLeft(0)((i:Int, j:String) => i+j)
triggers your conversion and works.
Edit: Here's how to implement the Numeric[String]:
implicit object StringNumeric extends math.Numeric[String] {
val num = math.Numeric.IntIsIntegral
def plus(x: String, y: String) = num.plus(x,y).toString
def minus(x: String, y: String) = num.minus(x,y).toString
def times(x: String, y: String) = num.times(x,y).toString
def negate(x: String): String = num.negate(x).toString
def fromInt(x: Int) = x.toString
def toInt(x: String) = x
def toLong(x: String) = toInt(x)
def toFloat(x: String) = toInt(x)
def toDouble(x: String) = toInt(x)
def compare(x:String,y:String) = num.compare(x,y)
}
scala> List("1","2","3") sum
res1: java.lang.String = 6
It works, but the result is a String.
Here's a quick explanation: implicit conversions apply to the types the convert from and to directly (e.g., String and Int in your case), and not to any parametrized type T[String] or T[Int] — unless implicit conversions have been defined for T itself, and it is not the case for lists.
Your implicit conversion does not apply in your two cases (and even if you had an implicit conversion from List[String] to List[Int], it wouldn't apply). It would automatically applied only when you need a value of type Int and you're passing String instead. Here, in the first case, the method sum asks for a Numeric[String] implicit parameter — an implicit conversion from String to Int does not come into play here.
Similar problem for your next attempt: the foldLeft on your collection requires a function of type (Int, String) => Int. Imagine the mess we would get into if, based on an implicit conversion from String to Int, the compiler automatically provided an implicit conversion from (Int, Int) => Int to (Int, String) => Int…
For all these cases, the easy way to fix it is to explicitly call .map(stringToInt) on your collection beforehand.
Related
I want to create a scala method parameter type that is a collection of multiple types which can all be converted to a common given type, but I have been unable to do that using implicit conversion, type classes, context bounds, and view bounds.
I have created a trait and class classes extending the trait, and I want to write a method that allows other developers to pass in a collection of instances that my code will process. However, I don't want the caller of my method to create a collection of instances. Instead, I want the caller to pass in a collection of tuples, where the tuples must be from a defined set of tuples.
The trait and case classes look like this:
sealed trait Widget {
type W
def identifier: W
def number: Int
}
case class CWidget(identifier: Char, number: Int) extends Widget {type W = Char}
case class SWidget(identifier: String, number: Int) extends Widget {type W = String}
case class CSWidget(identifier: (Char, String), number: Int) extends Widget {type W = (Char, String)}
and the method would look like this:
def getWidgets[W <% Widget](s: Seq[W]): Unit = ...
For now, the allowed tuples would have these types: (Char, Int), (String, Int), and (Char, String, Int). Eventually, I would like to be able to allow tuples that mix up the order like (Int, Char), but that's another story.
I created these implicit methods and brought them into scope with an import:
implicit def fromTuple(t: (Char, Int)) = ((c: Char, n: Int) => CWidget(c, n)) tupled t
implicit def fromTuple(t: (String, Int)) = ((s: String, n:Int) => SWidget(s, n)) tupled t
implicit def fromTuple(t: (Char, String, Int)) = ((c: Char, s: String, n: Int) => CSWidget((c, s), n)) tupled t
I tried this from the REPL:
getWidgets(Seq(('a',1),("string",2),('c',"string",3)))
and received this error:
<console>:26: error: No implicit view available from Product with Serializable => Widget.
Thanks in advance!
EDITED:
Here is the result of implementing the answer (Thanks, #gregghz !):
sealed trait Widget {
type W
def identifier: W
def number: Int
}
case class CWidget(identifier: Char, number: Int) extends Widget {type W = Char}
case class SWidget(identifier: String, number: Int) extends Widget {type W = String}
case class CSWidget(identifier: (Char, String), number: Int) extends Widget {type W = (Char, String)}
implicit def fromTupleCI(t: (Char, Int)): Widget = {
val (c, n) = t
CWidget(c, n)
}
implicit def fromTupleSI(t: (String, Int)): Widget = {
val (s, n) = t
SWidget(s, n)
}
implicit def fromTupleCSI(t: (Char, String, Int)): Widget = {
val (c, s, n) = t
CSWidget((c, s), n)
}
def getWidgets(s: Widget*): Unit = {
s.foreach { w => println(w) }
}
getWidgets(('a',1), ('b',2), ('c', "abc", 3), ("abcd", 4)
Here are the results:
CWidget(a,1)
CWidget(b,2)
CSWidget((c,abc),3)
SWidget(abcd,4)
This is good, since I didn't want to force the caller to create a Seq for the getWidgets method.
Most importantly, it checks the types of the arguments at compile time (Thanks, Static Typing!). I could have made the getWidgets arguments Any and used pattern matching, but that would have checked the arguments are run-time.
There are few problems here.
Your implicit conversion functions are converting from Tuple2[Char, Int] to Tuple2[Char, Int] => Widget. You want them to convert directly to a widget.
They should look more like this:
implicit def fromTuple(t: (Char, Int)): Widget = {
val (c, n) = t
CWidget(c, n)
}
implicit def fromTuple(t: (String, Int)): Widget = {
val (s, n) = t
SWidget(s, n)
}
implicit def fromTuple(t: (Char, String, Int)): Widget = {
val (c, s, n) = t
CSWidget((c, s), n)
}
However, this won't work as is. def fromTuple(t: (Char, Int)) and def fromTuple(t: (String, Int)) are the same type after type erasure occurs. This means the runtime can't distinguish between these two functions and it doesn't know which one to call. It turns out this is easy to fix. Just change the names of the functions to be unique:
implicit def fromTupleCI(t: (Char, Int)) = ...
implicit def fromTupleSI(t: (String, Int)) = ...
implicit def fromTupleCSI(t: (Char, String, Int) = ...
Next, since your call to getWidgets takes a Seq, the type of the Seq is first inferred. Since the various tuples have a common parent of Product your Seq is roughly inferred to be a Seq[Product]. There is no implicit conversion from Seq[Product] to a Seq[Widget]. There are two solutions to this.
You can explicitly specify the type parameter to Seq:
getWidgets(Seq[Widget](('a',1),("string",2),('c',"string",3)))
That will trigger the implicit conversion of the tuples to Widgets
You can also change the signature of getWidgets to take a varargs of widgets.
def getWidgets(s: Widget*): Unit = ...
getWidgets(('a',1), ("string",2), ('c',"string",3))
Again, this triggers implicit conversion where you want it to happen.
As a side note, view bounds (<%) is deprecated. In this case, you can simply replace <% with <: and get the same results.
Here is my code snippet:
implicit def trick(s: String): String = s.toUpperCase
def fun(s: String)(implicit f: String => String): String = f(s)
println(s"String is ${fun("abc")}")
When I run it, it prints "abc" instead of "ABC". What am I doing wrong here?
PS
However, if I run the next code
implicit val n: Int = 100
def add(n1: Int)(implicit n2: Int) = n1 + n2
add(7)
all implicit magic works just fine.
Normally this would work. The compiler would implicitly convert the implicit method to a function through eta-expansion. Say, if I wanted to require an implicit Int => List[Int] for some reason.
implicit def trick(i: Int): List[Int] = List.fill(5)(i)
def fun(i: Int)(implicit f: Int => List[Int]): List[Int] = f(i)
scala> fun(4)
res5: List[Int] = List(4, 4, 4, 4, 4)
But your problem is that there is another implicit String => String already in scope that comes from Predef. Namely =:=[String, String], which extends String => String. Because this already exists in scope as a function, the compiler sees no need to look for anything else. And, if you convert your implicit method to an implicit function, you will get an ambiguous implicits error:
implicit val trick: String => String = _.toUpperCase
scala> fun("abc")
<console>:19: error: ambiguous implicit values:
both method $conforms in object Predef of type [A]=> <:<[A,A]
and value trick of type => String => String
match expected type String => String
fun("abc")
Really though, having an implicit String => String is probably not a good idea. Use a type class that wraps a function, instead.
case class Trick[A](f: A => A)
implicit val trick = Trick[String](_.toUpperCase)
def fun(s: String)(implicit t: Trick[String]): String = t.f(s)
scala> println(s"String is ${fun("abc")}")
String is ABC
I have an method that expects (String, Double) as parameter
scala> def testTupleType(x: (String, Double)) = {}
testTupleType: (x: (String, Double))Unit
scala> val x: Int = 2
x: Int = 2
Then I try to pass the parameter to testTupleType method like that:
scala> val testTuple = ("String", x)
testTuple: (String, Int) = (String,2)
scala> testTupleType(testTuple)
<console>:11: error: type mismatch;
found : (String, Int)
required: (String, Double)
testTupleType(testTuple)
It show the error as expected. But when I pass the parameter inline:
scala> testTupleType(("String", x))
Do not have any error! I do not know is this because of an implicit conversion here?
There is no implicit conversion from Int to Double in scala. See 3.5.3
Weak Conformance in SLS.
In case of testTupleType(testTuple) error contains all information: (String, Int) is not a (String, Double).
With "inline" parameters:
testTupleType(("String", x))
It means:
testTupleType(Tuple2.apply("String", x))
Method apply accepts 2 type parameters:
def apply[T1, T2](_1: T1, _2: T2): (T1, T2)
testTupleType accepts (String, Double), so the result type of apply ((T1, T2)) should be (String, Double). After type inference:
testTupleType(Tuple2.apply[String, Double]("String", x))
or:
val a: (String, Double) = Tuple2.apply[String, Double]("String", x)
testTupleType(a)
Due to weak conformance you can use Int as Double here.
To understand the problem let's look at what -Xprint:typer shows:
In the first case you are passing a testTuple: (String, Int) = (String,2) into the method which expects: testTupleType: (x: (String, Double))Unit, but Scala doesn't have an implicit convertion from Tuple2[String, Int] to Tuple2[String, Double]:
val t = Tuple2[String, Int]("a", 2)
val a: (String, Double) = t
<console>:8: error: type mismatch;
found : (String, Int)
required: (String, Double)
val a: (String, Double) = t
^
Remember that (String, Int) is just a syntactic sugar for the compiler which calls Tuple2.apply.
So why the seconds snippets works? Because Scala desugars this into the Tuple2[String, Double]:
private[this] val res1: Unit = testTupleType(scala.Tuple2.apply[String, Double]("String", x.toDouble));
<stable> <accessor> def res1: Unit = res1
To summaries, in the first case you already have a Tuple2[String, Int] and Scala doesn't have an implicit convertion for it to Tuple2[String, Double], but you can make your own:
implicit def tsi2tdi(t: Tuple2[String, Int]): Tuple2[String, Double] = (t._1, t._2.toDouble)
and in the seconds case it sees the you have a String and an Int and you need to convert them into Tuple2[String, Double].
Update
No, it's called not by the apply method, it's called by the compiler. While compiling Scala performs different analysis phases, one of which is called typer. When scalac sees then you have an Int in the code, but what you want to get is a Double value, it knows that, according to the Weak Conformance rules mentioned by senia, it can get a Double from Int by calling toDouble method. That's not an implicit convertion in Scala point of view. If you remember primitive convertions were in C and Java, long before Scala
The problem is due to your code depending on implicit conversion in which case it does not happen when you pass the testTuple inline.
If you use val x:Double = 2 it should work.
I answered a question about a map of functions in Defining a Map from String to Function in Scala which led to a Function1[_, String] which I believe is correct as far as the typing question but possibly useless because I don't know how to invoke such a function:
scala> def f(x: Int) = x.toString
f: (x: Int)java.lang.String
scala> f(8)
res0: java.lang.String = 8
scala> val g: Function1[_, String] = f _
g: Function1[_, String] = <function1>
scala> g(8)
<console>:8: error: type mismatch;
found : Int(8)
required: _$1 where type _$1
g(8)
^
scala> val h: Function1[Int, String] = g
<console>:7: error: type mismatch;
found : (_$1) => String where type _$1
required: (Int) => String
val h: Function1[Int, String] = g
Is there any way to use g?
scala> g.asInstanceOf[Any => String](5)
res3: String = 5
It will work because all functions erase to the same thing: Function1[AnyRef, AnyRef]. When you specify it as Any, then passing an AnyVal will auto-box it on call (and it will be auto-unboxed at the method).
However, you do have to pass the correct parameter type. Or else...
scala> g.asInstanceOf[Any => String](true)
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Integer
I would say that it's like if you've cast an object of type String as Any, if you want to use a method defined in String you have to cast it back as a String.
You cast the function as a function that takes an argument of an existential type (which is what _ in a type context means), so you can't use it as a function that takes an Int. To use it as a function that takes an Int you have to cast it back.
The same problem exists when pattern matching with collections, or other generic classes:
def firstLength(collection: Any): Int ={
collection match {
// this is how you would have liked to write it
// case list: List[String] => list.head.length
// case map: Map[String, String] => map.values.head.length
// but this is how you have to write it because of type erasure
case list: List[_] => list.asInstanceOf[List[String]].head.length
case map: Map[_, _] => map.asInstanceOf[Map[String, String]].values.head.length
}
}
The type information isn't there, so you can't match on List[String], instead you have to match on the existential type List[_] (might be wrong on how you say that, it's not the generic type that is existential, I think) and then cast. This is more or less exactly the problem you have, the type you're after has been erased, and there's no way to get it back (unless you can use the same trick with ClassManifest that can be used to get around type erasure in cases like the one above [but not actually the case above, because it's a bit sloppy]).
I have seen a function named implicitly used in Scala examples. What is it, and how is it used?
Example here:
scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
| implicit def stringImpl = new Foo[String] {
| def apply(list : List[String]) = println("String")
| }
| implicit def intImpl = new Foo[Int] {
| def apply(list : List[Int]) = println("Int")
| }
| } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
scala> foo(1)
<console>:8: error: type mismatch;
found : Int(1)
required: List[?]
foo(1)
^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:8: error: could not find implicit value for evidence parameter of type
Foo[Double]
foo(List(1.0))
^
Note that we have to write implicitly[Foo[A]].apply(x) since the compiler thinks that implicitly[Foo[A]](x) means that we call implicitly with parameters.
Also see How to investigate objects/types/etc. from Scala REPL? and Where does Scala look for implicits?
implicitly is avaliable in Scala 2.8 and is defined in Predef as:
def implicitly[T](implicit e: T): T = e
It is commonly used to check if an implicit value of type T is available and return it if such is the case.
Simple example from retronym's presentation:
scala> implicit val a = "test" // define an implicit value of type String
a: java.lang.String = test
scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
b: String = test
scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
<console>:6: error: could not find implicit value for parameter e: Int
val c = implicitly[Int]
^
Here are a few reasons to use the delightfully simple method implicitly.
To understand/troubleshoot Implicit Views
An Implicit View can be triggered when the prefix of a selection (consider for example, the.prefix.selection(args) does not contain a member selection that is applicable to args (even after trying to convert args with Implicit Views). In this case, the compiler looks for implicit members, locally defined in the current or enclosing scopes, inherited, or imported, that are either Functions from the type of that the.prefix to a type with selection defined, or equivalent implicit methods.
scala> 1.min(2) // Int doesn't have min defined, where did that come from?
res21: Int = 1
scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>
scala> res22(1) //
res23: AnyRef{def min(i: Int): Int} = 1
scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt
Implicit Views can also be triggered when an expression does not conform to the Expected Type, as below:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Here the compiler looks for this function:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Accessing an Implicit Parameter Introduced by a Context Bound
Implicit parameters are arguably a more important feature of Scala than Implicit Views. They support the type class pattern. The standard library uses this in a few places -- see scala.Ordering and how it is used in SeqLike#sorted. Implicit Parameters are also used to pass Array manifests, and CanBuildFrom instances.
Scala 2.8 allows a shorthand syntax for implicit parameters, called Context Bounds. Briefly, a method with a type parameter A that requires an implicit parameter of type M[A]:
def foo[A](implicit ma: M[A])
can be rewritten as:
def foo[A: M]
But what's the point of passing the implicit parameter but not naming it? How can this be useful when implementing the method foo?
Often, the implicit parameter need not be referred to directly, it will be tunneled through as an implicit argument to another method that is called. If it is needed, you can still retain the terse method signature with the Context Bound, and call implicitly to materialize the value:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Passing a subset of implicit parameters explicitly
Suppose you are calling a method that pretty prints a person, using a type class based approach:
trait Show[T] { def show(t: T): String }
object Show {
implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }
def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}
case class Person(name: String, age: Int)
object Person {
implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
}
}
val p = Person("bob", 25)
implicitly[Show[Person]].show(p)
What if we want to change the way that the name is output? We can explicitly call PersonShow, explicitly pass an alternative Show[String], but we want the compiler to pass the Show[Int].
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
Starting Scala 3 implicitly has been replaced with improved summon which has the advantage of being able to return a more precise type than asked for
The summon method corresponds to implicitly in Scala 2. It is
precisely the same as the the method in Shapeless. The difference
between summon (or the) and implicitly is that summon can return a
more precise type than the type that was asked for.
For example given the following type
trait F[In]:
type Out
def f(v: Int): Out
given F[Int] with
type Out = String
def f(v: Int): String = v.toString
implicitly method would summon a term with erased type member Out
scala> implicitly[F[Int]]
val res5: F[Int] = given_F_Int$#7d0e5fbb
scala> implicitly[res5.Out =:= String]
1 |implicitly[res5.Out =:= String]
| ^
| Cannot prove that res5.Out =:= String.
scala> val x: res5.Out = ""
1 |val x: res5.Out = ""
| ^^
| Found: ("" : String)
| Required: res5.Out
In order to recover the type member we would have to refer to it explicitly which defeats the purpose of having the type member instead of type parameter
scala> implicitly[F[Int] { type Out = String }]
val res6: F[Int]{Out = String} = given_F_Int$#7d0e5fbb
scala> implicitly[res6.Out =:= String]
val res7: res6.Out =:= String = generalized constraint
However summon defined as
def summon[T](using inline x: T): x.type = x
does not suffer from this problem
scala> summon[F[Int]]
val res8: given_F_Int.type = given_F_Int$#7d0e5fbb
scala> summon[res8.Out =:= String]
val res9: String =:= String = generalized constraint
scala> val x: res8.Out = ""
val x: res8.Out = ""
where we see type member type Out = String did not get erased even though we only asked for F[Int] and not F[Int] { type Out = String }. This can prove particularly relevant when chaining dependently typed functions:
The type summoned by implicitly has no Out type member. For this
reason, we should avoid implicitly when working with dependently typed
functions.
A "teach you to fish" answer is to use the alphabetic member index currently available in the Scaladoc nightlies. The letters (and the #, for non-alphabetic names) at the top of the package / class pane are links to the index for member names beginning with that letter (across all classes). If you choose I, e.g., you'll find the implicitly entry with one occurrence, in Predef, which you can visit from the link there.