Would "type StringOrInt = String | Int" be nice?

Just reading Mechanics of unboxed union types in Scala and it asks the question.

Wouldn’t it be nice to be able to write a type like this:

type StringOrInt = String | Int

My immediate thought was no. How can you have an unboxed Int in a union type. Unboxed unions of AnyRef types is desirable as AnyRef is already a box. But it strikes me that a lot of our problems come from the failure of Scala’s type system to distinguish between a boxed value type and an unboxed value type.

The fact that an int needs to be boxed as Integer when assigned to a String | Int is no different than the fact that it needs to be boxed when it is assigned to a Number or to an Any.

Every time a primitive type P is upcast to a given type T which is a strict super type of P (i.e., P <: T but not T <: P), it needs to be boxed.

Still, boxing the Int as an Integer in String | Int is better than boxing it to an Integer inside a Right in an Either[String, Int].

I don’t see any problem, here.

But it strikes me that a lot of our problems come from the failure of Scala’s type system to distinguish between a boxed value type and an unboxed value type.

What do you mean? Scala has the same unified view that C# has. In C# int is a subtype of object, but if you assign an int value to field of type object then you get boxing. In Scala Int is a subtype of Any, but if you assign an Int value to a field of type Any then you get boxing. If you want to know more I can show you MSIL/ CIL/ whatever bytecodes.

You would either need support for tagged unions on VM level or have the permission to cast between primitive types and references. Casting would be extremely unsafe, so I don’t think any managed language would allow that. Tagged unions OTOH require extra space for tag. Dynamically typed languages allow to store any type of value in a field (and the type of field’s content can change) so I think they have to use tagged unions everywhere.

Considering that union types require support of pattern matching on them we must effectively have something that works like tagged unions (casting only makes sense when we know the singular type beforehand, but then what’s the point of union type?). Object headers are a kind of tags as they describe the actual class of an object, so they allow us to distinguish between types and do pattern matching.