What changes in type inference will Scala 3 bring? Currently documentation simply states TODO. For example,
Scala 2.13
scala> val i: Int = 42
val i: Int = 42
scala> val c: Char = 'a'
val c: Char = a
scala> List(i,c)
val res0: List[Int] = List(42, 97)
Scala 3 (dotty 0.24.0-RC1)
scala> val i: Int = 42
val i: Int = 42
scala> val c: Char = 'a'
val c: Char = a
scala> List(i,c)
val res0: List[AnyVal] = List(42, a)
Scala 2.13
scala> 42 == Some(42)
^
warning: comparing values of types Int and Some[Int] using `==` will always yield false
val res2: Boolean = false
Scala 3
scala> 42 == Some(42)
1 |42 == Some(42)
|^^^^^^^^^^^^^^
|Values of types Int and Some[Int] cannot be compared with == or !=
So as for your Equality
example it is actually caused by the new Multiversal Equality which pretty much means that if you have an Eql[A, B]
where A is B then type A can only be compared to things it has an Eql
instance for them (of the form Eql[A, C]
or Eql[C, A]
).
In terms of general type inference for scala 3, the main things are:
Union Types: We can now represent union types and expressions like
if (condition) 1 else "1"
should be of inferred as of type Int | String
.
Explicit Nulls: One of the new uses for union types is a way to describe nullable types, so for example we could write such a code in Java:
public String getUser(int id) {
if (id == 0) {
return "Admin";
}
return null;
}
And also in scala 2 we could write:
def getUser(id: Int): String = if (id == 0) return "Admin" else null
But in scala 3 such a method will also have to be declared as of type String | Null
to represent its nullability, and will not compile by default in newer versions of scala 3.
When working with Java it gets more complicated so if you want to know more about it I suggest reading in the link.
GADT: Similar to how @functionalInterface
works in java we know have GADTs.
That means that if you were to have a trait with one unimplemented method:
trait Fooable {
def foo(): Unit
}
You could create an instance of it by passing a lambda with that signature, so in this example:
val fooable: Fooable = () => print("Fooing")
There are a few more, including Context Functions, Implicit Conversions and Parameter untupling but those are the main ones.
Inferred types are now propagated through the remainder of the single parameter list, which means using multiple parameter lists to aid inference might not be necessary.
Scala 2.13
scala> def f[T](i: T, g: T => T) = g(i)
def f[T](i: T, g: T => T): T
scala> f(41, x => x + 1)
^
error: missing parameter type
Scala 3
scala> def f[T](i: T, g: T => T) = g(i)
def f[T](i: T, g: T => T): T
scala> f(41, x => x + 1)
val res0: Int = 42
I guess this change might be related to Allow inter-parameter dependencies #2079
Better inference when type parameters are not surfaced in terms
Scala 2.13
scala> def f[F <: List[A], A](as: F) = as
def f[F <: List[A], A](as: F): F
scala> f(List(42))
^
error: inferred type arguments [List[Int],Nothing] do not conform to method f's type parameter bounds [F <: List[A],A]
^
error: type mismatch;
found : List[Int]
required: F
Scala 3
scala> def f[F <: List[A], A](as: F) = as
def f[F <: List[A], A](as: F): F
scala> f(List(42))
val res0: List[Int] = List(42)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With