One of the strong features of scala is its ability of dealing with types. Maybe this is a bit unusual, but in my mind the value of an entity and its type is not something very different and can be treated on the same footing. In fact, the scala type system is Turing complete. It means that one can in principle perform any arbitrary calculation with types rather than with values. But can one define entities with more than one type?
You may use a
var with a union type.
But, I struggle to see a valid use case for that.
Maybe if you elaborate on why you want that we may provide a better solution.
Yes, I can explain a bit my motivation. Type system is a very good guard that assists programer to fish out compile and runt-time bugs. For instance, the impossibility of assigning a list to an integer helps to detect some logical errors. But we may want to expand this functionality, by adding more types or attributes to values so that we can use scala functionality to detect more complicated inconsistencies. For instance, one may have two float values, but one is kilograms and another is meter. Obviously, one should not assign meters to kilograms. Assume next, that we have two variables consistent in their basic type (float), subtype(kilogram), we may want to apply them to characterize fruits and elemental particles. Obviously, we never sum up the weight of oranges and electrons, therefore, we may want a sub-subtype that would forbid this operation. How can this be accomplished?
That is not having multiple types, that is just refined types.
In Scala 3 you could use opaque types defined with upper bounds. Like:
opaque type Kilogram = Double
opaque type Meter = Double
opaque type OrangeKilogram <: Kilogram = Double
opaque type ElementalParticleKilogram <: Kilogram = Double
In Scala 2 you could use AnyVals with implicit conversions to simulate the subtyping relationships, but you may end up with undesired boxing at runtime.
Just a naive question, what is the difference between refined and multiple types?
In Iron, this implemented by using heavily typeclasses and Scala 3 's opaque types + inline.
IIRC Refined relies on shapeless (a famous lib in Scala for generic programming).
About your second question, I don’t know what you mean by “multi types”.
This observation was also made above by @BalmungSan, but what make refined types so different from multiple types? Also, you seem suggesting libraries, but I am more interested in the native scala functionality, albeit somewhat limited. I like the answer of @bvenners in this respect, but it is worrying that one needs scala 3 for this.
I’m suggesting you to look at the source code to see how these libs implement this concept very differently.
Actually, the method to implement such feature changed heavily between Scala 2 and 3. Scala 3 simplified the process but if you’re only interested in Scala 2 then I think you should look at Refined and Shapeless since they are Scala 2-compatible. As far as I know, in Scala 2 these kind of feature is doable using macros.
Also I still don’t get what you mean by multi types. As @BalmungSan said, your definition corresponds to refined types.
As @Iltotore said, it is not clear what you mean with multiple types, but the use case you mentioned corresponds to refined types.
Now, in Scala a variable technically has multiple types, where all of those types have a subtype / super type relationship between them. You can forgot some of those types by abscrbing the type of a variable to some specific super type, that way you loose all the subtypes from that point in the chain.
But, since all those types are in a single chain and usually one refer to them with the most specific type we care, we have the perception that they have a single type.
Thus, when you said multiple types I imagened something like “I want Foo to be sometimes an Int and sometimes a String” but that is also a single type, a sum one, like
Either or an union.
So then I thought you meant having the possibility of changing the type of a variable, but that is just creating a new one and shadowing the old one. So it really wasn’t clear to me.
Now, again, what you want is not multiple types, rather the possibility of creating more specific types; and that is just what we always do.
You don’t need fancy features at all. Those are a performance optimization to ensuring at the end having just a plain double in runtime. But the concept can be expressed with plain traits and classes.