Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Dotty decide how to infer/when to widen Union Types?

Widening Union Types have been discussed here but I can't seem to find an answer to the following case

Let's start by looking at the following

val x = List(1, 2, "a")

This heterogeneous list is inferred as List[Any] Just like it would in Scala 2

However the following

val x2 = List(List(1, 2), Vector("a", "b"))

is inferred as List[scala.collection.immutable.AbstractSeq[Int | String]]

This is rather confusing behavior. Why does two disjoint types' LUB get inferred as Any in one case but a union type in another?

If it is just a design decision, are there any such cases that one should be aware of ?

like image 474
sinanspd Avatar asked Sep 16 '20 19:09

sinanspd


1 Answers

smarter states

we avoid inferring union types for the same reason we avoid inferring singleton types, because sometimes they're "too precise"

My interpretation of this statement is that it makes more sense to type List(1,2) as List[Int] instead of List[1 | 2], or List(new Cat, new Dog) as List[Animal] instead of List[Cat | Dog].

See also Dmytro's comment from related question (of mine)

Quote from guillaume.martres.me/talks/dotty-tutorial/#/1/13 (slide 15 "Type inference and union types"): "By default, Dotty does not infer union types, they are approximated by a non-union supertype. Union types can be "too precise" and prevent legitimate code from compiling"

Also see mention at 23:38 of the talk "Dotty and types: the story so far".

However widening of union is performed only once to avoid infinite LUB as per smarter:

when we do the widening once, the resulting type might have a union somewhere (like the example in the section Join of a union type in the doc), we won't widen that if we did do the widening recursively, we could get an infinite lub indeed

like image 62
Mario Galic Avatar answered Oct 17 '22 01:10

Mario Galic