Scala type inference and implicit conversions - scala

The following code works:
scala> import scala.language.implicitConversions
import scala.language.implicitConversions
scala> implicit val longToInt = (l: Long) => l.toInt
longToInt: Long => Int = $$Lambda$1821/0x000000010086e840#52bd9a27
scala> def printInt(n: Int) = println(n)
printInt: (n: Int)Unit
scala> val opt: Option[Long] = None
opt: Option[Long] = None
scala> val n = opt.getOrElse(0L)
n: Long = 0
scala> printInt(n)
0
However, the compiler throws a type mismatch error if we nest the getOrElse expression inside of the function call:
scala> printInt(opt.getOrElse(0L))
<console>:16: error: type mismatch;
found : AnyVal
required: Int
printInt(opt.getOrElse(0L))
^
Why does opt.getOrElse(0L) have type AnyVal?
Scala 2.12.8

When you write
printInt(opt.getOrElse(0L))
opt.getOrElse(0L) is typed with expected type Int. Option#getOrElse's signature is
getOrElse[B >: A](default: ⇒ B): B
Because it's generic, the compiler tries to find B such that opt.getOrElse[B](0L) has type Int. So B has to satisfy constraints B >: Long (because A in the above signature is Long) and B <: Int (from the return type). Obviously there's no such B. Scala specification says this must be an error, but doesn't say which, and here the compiler happens to report it after guessing B = AnyVal.
Another way to fix it is to specify the expected type for opt.getOrElse(0L):
printInt(opt.getOrElse(0L): Long)
Or the type parameter:
printInt(opt.getOrElse[Long](0L))

The signature of getOrElse is:
def getOrElse[B1 >: B](key: A, default: ⇒ B1): B1
printInt(opt.getOrElse(0L)) tells Scala that B1 ought to be Long, but Long is not a super-type of Int. The common supertype instead is AnyVal. Therefore you cannot make that assignment.
Try casting the result to a Long instead:
printInt(opt.getOrElse(0L).toLong)

Related

How does Scala resolve generic types automatically?

Please consider the following 2 lines of code:
def foo[F[B],A](fa: F[A]): String = fa.toString
println(foo(10))
It prints 10. What I wonder, is how it even compiles. I am trying to understand how Scala resolves the generics here. I mean, what are A, B, and F?
When looking at Intellij, it seems like 10 is converted from a Scala Int, to a Java Integer. But I don't know how the Java Integer is converted to any F[A] (Java Integer is not a generic type), as foo expects to receive.
how the Java Integer is converted to any F[A](Java Integer is not generic type), as foo expects to receive.
Java Integer is subtype of Comparable[Integer]
public final class Integer extends Number implements Comparable<Integer>
Scala 2.13 infers F = Any and A = Nothing
scala> def foo[F[_],A](fa: F[A]) = fa
def foo[F[_], A](fa: F[A]): F[A]
scala> foo(10) // print
foo[Any, Nothing](10) // : Any
scala> foo(10)
val res9: Any = 10
This inference happens because of the presence of implicit conversion
implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Integer]
If we hide this conversion it will not compile
scala> implicit val int2Integer = null
val int2Integer: Null = null
scala> foo(10)
^
error: no type parameters for method foo: (fa: F[A]): F[A] exist so that it can be applied to arguments (Int)
--- because ---
argument expression's type is not compatible with formal parameter type;
found : 10
required: ?F[?A]
^
error: type mismatch;
found : Int(10)
required: F[A]
However note despite the fact that int2Integer made it compile, the implicit conversion did not actually take place (which might be a bug)
scala> foo(10)
val res9: Any = 10
where res9 should have been typed as Comparable[Integer] instead of Any.
Scala 3 (Dotty) infers F = Comparable and A = Integer as per -Xprint:typer
foo[Comparable, Integer](int2Integer(10))
and the implicit conversion is indeed applied
Starting dotty REPL...
scala> def foo[F[_],A](fa: F[A]) = fa
def foo[F[_$1], A](fa: F[A]): F[A]
scala> foo(10)
val res0: Comparable[Integer] = 10
If you're using Scala 2.12 or previous, there is an implicit conversion from Int to RichInt in order to provide additional methods on Java's Int.
The definition looks like
final class RichInt extends AnyVal with ScalaNumberProxy[Int] with RangedProxy[Int]
So here F[A] could be ScalaNumberProxy[A] with RangedProxy[A] and B would be Int. Here is an explicit example using only ScalaNumberProxy for simplicity.
import scala.runtime.ScalaNumberProxy
def foo[F[B],A](fa: F[A]): String = fa.toString
println(foo[ScalaNumberProxy, Int](10))
If using Scala 2.13+, RichInt appears to have been renamed, but there is certainly a similar implicit conversion that applies.

Scala error: type mismatch; found : java.util.List[?0] required: java.util.List[B]

I have below Scala code.
This function defines type parameter type B which is subclass of A. It converts java.util.List[A] into java.util.List[B].
import java.util
import java.util.stream.Collectors
class Animal
class Dog extends Animal
class Cat extends Animal
object ObjectConversions extends App {
import java.util.{List => JList}
implicit def convertLowerBound[ B <: Animal] (a: JList[Animal]): JList[B] = a.stream().map(a => a.asInstanceOf[B]).collect(Collectors.toList())
val a= new util.ArrayList[Animal]()
a.add(new Cat)
convertLowerBound[Cat](a)
}
When I compile this program I get below error.
<console>:15: error: type mismatch;
found : java.util.List[?0]
required: java.util.List[B]
Note: ?0 >: B, but Java-defined trait List is invariant in type E.
You may wish to investigate a wildcard type such as `_ >: B`. (SLS 3.2.10)
implicit def convertLowerBound[ B <: Animal] (a: JList[Animal]): JList[B] = a.stream().map(a => a.asInstanceOf[B]).collect(Collectors.toList())
What is wrong with my program. How can I resolve this error
It looks like type erasure happened (from Animal to ?0) when using java.util.stream.Stream.map, regardless B or concrete type passed in, possibly due to incompatibility between Scala type inference and Java type inference.
When calling Java method and you still want generic type inference, you need to pass the generic type specifically:
def convertLowerBound[ B <: Animal] (a: JList[Animal]): JList[B] = a.stream().map[B](a => a.asInstanceOf[B]).collect(Collectors.toList[B]())
Then you can do your operation successfully:
scala> def convertLowerBound[ B <: Animal] (a: JList[Animal]): JList[B] = a.stream().map[B](a => a.asInstanceOf[B]).collect(Collectors.toList[B]())
convertLowerBound: [B <: Animal](a: java.util.List[Animal])java.util.List[B]
scala> convertLowerBound[Cat](a)
res30: java.util.List[Cat] = [Cat#6325af19, Dog#6ff6743f]
On the other hand, your conversion isn't really useful, because during runtime, all the generic type will be erased so List[A] or List[B] will be the same after compiling (they will become List of Object. You can take a look at the compiled bytecode). You can simply do direct casting on your List instead of on each element:
def convertLowerBound[B <: Animal : TypeTag] (a: JList[Animal]) = a.asInstanceOf[JList[B]]
Then you can do your use case successfully:
scala> a.add(new Cat())
res16: Boolean = true
scala> convertLowerBound[Cat](a)
res17: java.util.List[Cat] = [Cat#6325af19]
However when there is a type mismatch, e.g. you add a Dog in the List and try to cast it as a List of Cat, an error will occur, only when you try to access the element:
scala> a.add(new Dog())
res19: Boolean = true
scala> convertLowerBound[Cat](a)
res20: java.util.List[Cat] = [Cat#6325af19, Dog#6ff6743f]
scala> convertLowerBound[Cat](a).get(1)
java.lang.ClassCastException: Dog cannot be cast to Cat
... 28 elided

A => Class[A] using ClassTag?

Looking at ClassTag#runtimeClass, it has a return type of Class[_], i.e. a Class with, as I understand, a wildcard parameter.
I tried to implement a method: A => ClassTag[A]:
import scala.reflect._
scala> def f[A](x: A)(implicit ev: ClassTag[A]) = ev.runtimeClass
f: [A](x: A)(implicit ev: scala.reflect.ClassTag[A])Class[_]
But, the output of the def's definition is, as the docs show, Class[_].
Is it possible to change f such that its return type is Class[A]? If not, then why is it not possible?
Unless you change the signature of f, your only option is to cast the Class[_] to a Class[A].
There is literally only one method in the entire Scala standard library that returns a Class[A], and that is classOf. f[A] cannot be re-written to use classOf[A] since it is a special compiler method and is incompatible with generic type parameters that may not be classes. You would simply get an error:
scala> def f[A: ClassTag](x: A) = classOf[A]
<console>:10: error: class type required but A found
def f[A: ClassTag](x: A) = classOf[A]
^
The best you can get without casting is using x.getClass, but that will return a Class[_ <: A] (no ClassTag needed).
scala> def f[A](x: A): Class[_ <: A] = x.getClass
f: [A](x: A)Class[_ <: A]
scala> f(1)
res8: Class[_ <: Int] = class java.lang.Integer
scala> f(List(1, 2, 3))
res9: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon
You might ask, why _ <: A?
The answer to that question is also the reason why your definition of f doesn't really make sense. If A is an Int, it makes sense to be able to return a Class[A] because Int is a class. But what if A is a List[Int]? List[Int] is not a class, it's a type. The class is List, but A != List, therefore we cannot return a Class[A] consistently. We can, however, have an upper-bound of A on the type parameter of Class.

Is PartialFunction orElse looser on its type bounds than it should be?

Let's define a PartialFunction[String, String] and a PartialFunction[Any, String]
Now, given the definition of orElse
def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1]
I would expect not to be able to compose the the two, since
A → String
A1 → Any
and therefore the bound A1 <: A (i.e. Any <: String) doesn't hold.
Unexpectedly, I can compose them and obtain a PartialFunction[String, String] defined on the whole String domain. Here's an example:
val a: PartialFunction[String, String] = { case "someString" => "some other string" }
// a: PartialFunction[String,String] = <function1>
val b: PartialFunction[Any, String] = { case _ => "default" }
// b: PartialFunction[Any,String] = <function1>
val c = a orElse b
// c: PartialFunction[String,String] = <function1>
c("someString")
// res4: String = some other string
c("foo")
// res5: String = default
c(42)
// error: type mismatch;
// found : Int(42)
// required: String
Moreover, if I explicitly provide the orElse type parameters
a orElse[Any, String] b
// error: type arguments [Any,String] do not conform to method orElse's type parameter bounds [A1 <: String,B1 >: String]
the compiler finally shows some sense.
Is there any type system sorcery I'm missing that causes b to be a valid argument for orElse? In other words, how come that A1 is inferred as String?
If the compiler infers A1 from b then it must be Any, so where else does the inference chain that leads to String start?
Update
After playing with the REPL I noticed that orElse returns an intersection type A with A1 when the types don't match. Example:
val a: PartialFunction[String, String] = { case "someString" => "some other string" }
// a: PartialFunction[String,String] = <function1>
val b: PartialFunction[Int, Int] = { case 42 => 32 }
// b: PartialFunction[Int,Int] = <function1>
a orElse b
// res0: PartialFunction[String with Int, Any] = <function1>
Since (String with Int) <:< String this works, even though the resulting function is practically unusable. I also suspect that String with Any is unified into Any, given that
import reflect.runtime.universe._
// import reflect.runtime.universe._
typeOf[String] <:< typeOf[String with Any]
// res1: Boolean = true
typeOf[String with Any] <:< typeOf[String]
// res2: Boolean = true
So that's why mixing String and Any results into String.
That being said, what is going on under the hood? Under which logic are the mismatching types unified?
Update 2
I've reduced the issue to a more general form:
class Foo[-A] {
def foo[B <: A](f: Foo[B]): Foo[B] = f
}
val a = new Foo[Any]
val b = new Foo[String]
a.foo(b) // Foo[String] Ok, String <:< Any
b.foo(a) // Foo[String] Shouldn't compile! Any <:!< String
b.foo[Any](a) // error: type arguments [Any] do not conform to method foo's type parameter bounds [A <: String]
You're getting this upside down.
You can always pass to a method requiring a parameter of type A any argument of type B <: A, i.e. any subtype of A. That is if you have
def foo(a: Animal)
you can pass a Dog to foo, because Dog <: Animal.
In the same way, if you have
def foo(l: List[Animal])
you can pass a List[Dog] to it, because List is covariant with its type parameter and since Dog <: Animal, then List[Dog] <: List[Animal]
Now if you have
def foo(pf: PartialFunction[String, String])
you can pass a PartialFunction[Any, String], because PartialFunction is contravariant with the first type parameter and covariant with the second. Since Any >: String, then PartialFuncion[Any, String] <: PartialFunction[String, String].
Now, for the type bounds, the compiler will try to infer A1 and B1, such that
A1 is subtype of A
B2 is subtype of B
To do so, it will look for:
the greatest common subtype of Any and String, since A and A1 are in contravariant position
the least common supertype of String and String, since B and B1 is covariant position
Results
A1 → String
B1 → String
The case in which you compose a PartialFunction[String, String] with a PartialFunction[Int, Int] is an odd-looking case of the previous example, in which:
the greatest common subtype of String and Int is String with Int, i.e. the interesection of the two types, which is subtype of both (in this case is pretty much as saying Nothing: being both a String and an Int doesn't seem very likely)
the least common supertype of String and Int is Any
therefore
val a: PartialFunction[String, String] = ...
val b: PartialFunction[Int, Int] = ...
a orElse b // PartialFunction[String with Int, Any] // as expected, although not very useful...
I was going to say that PartialFunction[Any, String] is a subtype of PartialFunction[String, String] because of contra-variance if I understand correctly. This would explain the behavior described in your question before the update, but you got me all mixed up with this union type stuff.
I don't even know what the hell String with Int means!
This is of course vague and only my humble opinion. Suggestions and comments are appreciated.
Taking from this SO question. (How to know if an object is an instance of a TypeTag's type?)
import scala.reflect.runtime.universe._
implicit class MyInstanceOf[U: TypeTag](that: U) {
def myIsInstanceOf[T: TypeTag] =
typeOf[U] <:< typeOf[T]
}
We have a proper way to check isInstanceOf without erasure.
val b: PartialFunction[Any, String] = { case _ => "default" }
b.myIsInstanceOf[PartialFunction[String, String]] //true
And it only makes sense. If you have a function from Any => String, then it accepts any input. So it also accepts String input. That's why it can also be treated as a Function from String => String. Basically it can be treated as T => String for any T.
So in the end the compiler agrees on A -> String and A1 -> String.
a.orElse[String,String](b) //works
Edit: Final thoughts
You should not think of A1 <: A as a restriction. It will only infer the type of the resulting PartialFunction.
There is no way that orElse cannot be applied. Both PF involved are contra-variant on A and therefore a common subtype for BOTH can always be found that satisfies A1 <: A.
I think an analogy would be addition of fractions, where you think, oh, they have not a common denominator and therefore can not be added. Both fractions can be adjusted (or: seen differently) to have a common denominator. The compiler although wants to find the smallest common denominator and not resort to the easy way with multiplying with the other denominator. (A with A')
For the other type B it's the same. Both are co-variant and therefore a common super type can also always be found. Any in the worst case.
You already typed this in, but:
scala> val a: PartialFunction[String, String] = { case "a" => "b" }
a: PartialFunction[String,String] = <function1>
scala> val b: PartialFunction[Any, String] = { case 1 => "one" }
b: PartialFunction[Any,String] = <function1>
scala> a orElse b
res0: PartialFunction[String,String] = <function1>
scala> a orElse[String,String] b
res1: PartialFunction[String,String] = <function1>
scala> a orElse[Any,String] b
<console>:10: error: type arguments [Any,String] do not conform to method orElse's type parameter bounds [A1 <: String,B1 >: String]
a orElse[Any,String] b
^
scala> import reflect.runtime._ ; import universe._
import reflect.runtime._
import universe._
scala> typeOf[PartialFunction[Any,String]] <:< typeOf[PartialFunction[String,String]]
res3: Boolean = true
Because of the contravariant type param, you can use PF[Any, String] here.
To answer the question, where does it say what it will pick?
http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#local-type-inference
E.g., it promises to infer a maximal A1 in contravariant position, but still conforming to the constraint <: A.

When to use `with` for bounding type parameters instead of `<:` or `<:<` in Scala?

In another question, I'm advised to use with in a place where one normally uses <: or <:<. So instead of defining functions in either of the following two ways:
scala> def f[A,C <: Seq[A]](xs: C) = 0
f: [A, C <: scala.collection.immutable.Seq[A]](xs: C)Int
scala> f(List(1))
<console>:54: error: inferred type arguments [Nothing,List[Int]] do not conform to method f's type parameter bounds [A,C <: scala.collection.immutable.Seq[A]]
f(List(1))
^
scala> implicit def f[A,C](xs: C)(implicit ev: C <:< Seq[A]) = new { def foo = 0 }
f: [A, C](xs: C)(implicit ev: <:<[C,scala.collection.immutable.Seq[A]])java.lang.Object{def foo: Int}
scala> List(0) foo
<console>:54: error: Cannot prove that List[Int] <:< scala.collection.immutable.Seq[A].
List(0) foo
^
scala> f(List(0)) foo
res17: Int = 0
One can do:
scala> implicit def f[A,C](xs: C with Seq[A]) = new { def foo = 0 }
f: [A, C](xs: C with scala.collection.immutable.Seq[A])java.lang.Object{def foo: Int}
scala> List(0) foo
res18: Int = 0
My question is: besides the above particular case, when should one use with instead of <: or <:< on the type parameter? Why not always use with instead? I'm looking for a discussion of the nuances among the alternatives here. Thanks.
The meanings are entirely different. C <: Seq[A] means that C is a subtype of Seq[A], as you know; xs: C with Seq[A] doesn't put any bound on C, but means that xs should be both a C and a Seq[A]. Therefore you should normally use the one you actually mean.
In def f[A,C <: Seq[A]](xs: C) the problem is that Scala's compiler can't infer A because it doesn't appear explicitly in the type of arguments. I don't see any reason in principle it couldn't infer A; it just doesn't currently. Replacing the type with C with Seq[A] means A now appears in the type of xs and allows the compiler to infer A. So if you really mean the bound, but A to be inferred, you actually need to write
implicit def f[A,C <: Seq[A]](xs: C with Seq[A])
instead of your third definition, and this is what the answer to the linked question does.