i'm trying to understand the behavior of the compiler in this situation
object ImplicitTest extends App {
def foo[T](implicit x: (String => T)): T = ???
implicit val bar = (x: String) => x.toInt
foo
}
the code above does not compile and gives the following error:
ambiguous implicit values: both method $conforms in object Predef of
type [A]⇒ <:<[A,A] and value bar in object ImplicitTest of type ⇒ String ⇒
Int match expected type String ⇒ T
as the error says my implicit value is conflicting with another implicit defined in Predef... based on this it seems there is no way to declare an implicit parameter to a function converting a value from a known type to an unknown (generic) type.
Is this due to some technical limitation on the compiler or is just the way it is supposed to work, and i'm violating some constraints i'm not aware of?
You're not providing a type parameter to foo when you call it (and there is no other way to infer it, for the following reason), so the compiler is having trouble finding the right one, and the right implicit.
You have the implicit bar: String => Int in scope, but you also have implicits in Predef that create instances of =:= and <:< which both extend A => B, and create implicit String => As. The compiler is looking for some implicit function String => T for foo, but it's not sure which one, and you have multiple in scope. bar will not take precedence because you haven't specified the specific String => T it's looking for.
This will work:
def foo[T](implicit x: (String => T)): T = ???
implicit val bar = (x: String) => x.toInt
foo[Int]
Related
In my project, I need to write a generic class, which in a single method handles some types with its handler in a special way (Numeric is used for clarity in the example).
class A[T](val a:T){
def doSomething(b:T):T = a match{
case a : Int => doSomethingWithIntOrDouble(b)
case a : Double => doSomethingWithIntOrDouble(b)
case _ => b
}
def doSomethingWithIntOrDouble(b:T)(implicit ev:Numeric[T]):T =
ev.plus(a,b)
}
<console>:13: error: could not find implicit value for parameter ev: Numeric[T]
case a : Int => doSomethingWithIntOrDouble(b)
^
<console>:14: error: could not find implicit value for parameter ev: Numeric[T]
case a : Double => doSomethingWithIntOrDouble(b)
I think this happens because the compiler picks up the type parameter but not the actual one. Tell me, is there any way around this?
PS Okay If we assume that the answer is correct, then it is necessary to overload the dosomething method to achieve polymorphism.
class A[T](val a:T){
def doSomething(b:T)(implicit ev:Numeric[T]):T = ev.plus(a,b)
def doSomething(b:T):T = b
}
But in this case, another problem arises.
scala> a.doSomething(2)
<console>:13: error: ambiguous reference to overloaded definition,
both method doSomething in class A of type (b: Int)Int
and method doSomething in class A of type (b: Int)(implicit ev: Numeric[Int])Int
match argument types (Int)
a.doSomething(2)
I am not completely sure this is want your want, but I hope it helps.
Basically, you need to forward the evidence that the T type is a Numeric to the outer method. But, you also have to handle the case where it is not.
For that case, you can provide a default value for the implicit parameter like this:
class A[T](val a: T) {
def doSomething(b: T)(implicit ev: Numeric[T] = null): T = Option(ev) match {
case Some(ev) => doSomethingWithNumeric(b)(ev)
case None => b
}
def doSomethingWithNumeric(b: T)(implicit ev: Numeric[T]): T =
ev.plus(a, b)
}
It seems to work.
(new A(10)).doSomething(100) // res: Int = 110
(new A("hey")).doSomething("world") // res: String = "world"
Note that, if you will have many methods, maybe a cleanest solution would be to make A a trait with two implementations, one for numeric types and other for no numeric types.
Make the constructors of both sub classes private and create a factory for A in the companion object which ask for the implicit numeric parameter, and if found it will return a new instance of the numeric subclass.
I'm trying to call this set method documented here, in the Java library jOOQ, with signature:
<T> ... set(Field<T> field, T value)
This Scala line is a problem:
.set(table.MODIFIED_BY, userId)
MODIFIED_BY is a Field<Integer> representing the table column. userId is Int. Predef has an implicit conversion from Int to Integer, so why doesn't it use it? I get this:
type mismatch; found: org.jooq.TableField[gen.tables.records.DocRecord,Integer]
required: org.jooq.Field[Any]
Note: Integer <: Any
(and org.jooq.TableField[gen.tables.records.DocRecord,Integer] <:
org.jooq.Field[Integer]), but Java-defined trait Field is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
Update - About Vinicius's Example
Rather than try to explain this in comments, here is a demonstration that there is no implicit conversion being called when you use a type with covariant parameter, like List[+T]. Let's say I put this code in a file, compile, and run it...
case class Foo(str: String)
object StackOver1 extends App {
implicit def str2Foo(s: String): Foo = {
println("In str2Foo.")
new Foo(s)
}
def test[T](xs: List[T], x: T): List[T] = {
println("test " + x.getClass)
xs
}
val foo1 = new Foo("foo1")
test(List(foo1), "abc")
}
You'll see that it calls test, but never the implicit conversion from String "abc" to Foo. Instead it's picking a T for test[T] that is a common base class between String and Foo. When you use Int and Integer it picks Any, but it's confusing because the runtime representation of the Int in the list is Integer. So it looks like it used the implicit conversion, but it didn't. You can verify by opening a Scala prompt...
scala> :type StackOver1.test(List(new java.lang.Integer(1)), 2)
List[Any]
I don't know anything aboutjOOQ, but I think the issue is that Scala does not understand java generics very well. Try:
scala> def test[T](a : java.util.ArrayList[T], b: T) = { println(a,b) }
scala> val a = new java.util.ArrayList[Integer]()
scala> val b = 12
scala> test(a,b)
<console>:11: error: type mismatch;
found : java.util.ArrayList[Integer]
required: java.util.ArrayList[Any]
Note: Integer <: Any, but Java-defined class ArrayList is invariant in type E.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
test(a,b)
Sounds familiar??
And to fix, just inform the type T to call the method: test[Integer](a,b) works fine.
EDIT:
There a few things involved here:
Erasure -> When compiled the type of the generic will disappear by erasure. The compiler will use Object which Scala, will treat as Any. However a ArrayList[Integer] is not an ArrayList[Any], even though Integer is any. The same way that TableField[gen.tables.records.DocRecord,Integer] is not a Field[Any].
Type inference mechanism -> it will figure out what type T should be and to do that it will use the intersection dominator of the types passed (in our case the first common ancestor). Page 36 of Scala Language Spec, which in our examples above will lead use to Any.
Implicit conversion -> it is the last step and would be called if there was some type to be converted to another one, but since the type of the arguments were determined to be the first common ancestor, there is no need to convert and we will never have a implicit conversion if we don't force the type T.
A example to show how the common ancestor is used to determine T:
scala> def test[T](a: T, b: T): T = a
scala> class Foo
scala> class Boo extends Foo
scala> test(new Boo,new Foo)
res2: Foo = Boo#139c2a6
scala> test(new Boo,new Boo)
res3: Boo = Boo#141c803
scala> class Coo extends Foo
scala> test(new Boo,new Coo)
res4: Foo = Boo#aafc83
scala> test(new Boo,"qsasad")
res5: Object = Boo#16989d8
Summing up, the implicit method does not get called, because the type inference mechanism, determines the types before getting the argument and since it uses the common ancestor, there is no need for a implicit conversion.
Your code produces an error due to erasure mechanism which disappear with the type information that would be important to determine the correct type of the argument.
#RobN, thanks for questioning my answer, I learned a lot with the process.
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.
I would like to define a method parameterized with type T that has behavior dependent on what implicit argument can be found of type Box[T]. The following code has this method defined as foo. When called with foo[Int] or foo[String] it will without issue return 1 or "two" as expected.
Where things get weird is with the method bar. It is defined as returning an Int, but instead of foo[Int] I have just foo. My hope was that the compiler would infer that T must be of type Int. It does not do that and instead fails:
bash $ scalac Code.scala
Types.scala:15: error: ambiguous implicit values:
both value one in object Main of type => Main.Box[Int]
and value two in object Main of type => Main.Box[java.lang.String]
match expected type Main.Box[T]
def bar: Int = foo
^
one error found
What is causing this error? Replacing foo with foo[Int] compiles fine. The simpler situation where there is no Box[T] type also compiles fine. That example is also below and uses argle and bargle instead of foo and bar.
object Main extends Application {
case class Box[T](value: T)
implicit val one = Box(1)
implicit val two = Box("two")
def foo[T](implicit x: Box[T]): T = {
x.value
}
// does not compile:
// def bar: Int = foo
// does compile
def bar: Int = foo[Int]
println(bar)
// prints 1
// the simpler situation where there is no Box type
implicit val three = 3
implicit val four = "four"
def argle[T](implicit x: T): T = x
def bargle: String = argle
println(bargle)
// prints "four"
}
What is going on in this snippet that causes this behavior? What about this interaction of implicit arguments, type inference, and erasure is causing problems? Is there a way to modify this code such that the line def foo: Int = bar works?
Someone else will have to explain why the type inference mechanism cannot handle that case, but if you are looking to cleanup your code you could probably do this:
object Test extends App {
case class Box[T](value: T)
implicit val one: Box[Int] = Box(1)
implicit val two: Box[String] = Box("two")
def foo[T : Box]: T = implicitly[Box[T]].value
val bar = foo[Int]
}
Note that:
I removed the type annotation from bar so you are really just indicating the type once (just in a different spot than you wanted)
I am using App instead of deprecated Application
Using a context bound in the type signature of foo
This might be related to SI-3346, though there it is implicit arguments to implicit conversions, and here you have a single implicit.
I would like an explanation of difference for example between this declaration:
class Clazz(param1: String, param2: Integer)
and this one:
class Clazz(param1: String)(param2: Integer)
Does second declaration affect just the way of instantiating the objects or is there any deeper reason I don't know about.
One reason I thought about would be multiple variable length of parameters for example:
class Clazz(param1: String*)(param2: Integer*)
So are there any others?
#1 Type inference. It goes from left to right and is done per parameter list.
scala> class Foo[A](x: A, y: A => Unit)
defined class Foo
scala> new Foo(2, x => println(x))
<console>:24: error: missing parameter type
new Foo(2, x => println(x))
^
scala> class Foo[A](x: A)(y: A => Unit)
defined class Foo
scala> new Foo(2)(x => println(x))
res22: Foo[Int] = Foo#4dc1e4
#2 Implicit parameter list.
scala> class Foo[A](x: A)(implicit ord: scala.Ordering[A]) {
| def compare(y: A) = ord.compare(x, y)
| }
defined class Foo
scala> new Foo(3)
res23: Foo[Int] = Foo#965701
scala> res23 compare 7
res24: Int = -1
scala> new Foo(new {})
<console>:24: error: No implicit Ordering defined for java.lang.Object.
new Foo(new {})
^
In the second version you are declaring a curried primary constructor for Clazz. So the difference between the two versions is the same as difference between "normal" and curried functions in Scala, i.e.
def foo(param1: String, param2: Int)
def foo(param1: String)(param2: Int)
Most of the time both declarations can be used interchangeably but if you often need to curry function then it makes more sense to declare it in curried form. Note you can also convert a normal function or even constructor into a curried form, for e.g you could transform your normal Clazz constructor into curried form using this:
(new Clazz(_, _)).curried
You also need multiple parameter lists if you are passing an implicit value (as the keyword implicit applies to the complete parameter list)