I’m going over the original SIP again, and I’m wondering whether the original motivation can be satisfied with a simpler solution.
The SIP explains that the original motivation is to be able to make the compiler help differentiate between different type aliases of the same type – for instance, Id
and Password
, both are String
. One solution to this are wrapper case classes, but since they may incur a performance penalty, a new solution was needed.
Opaques seem to me mostly of a better-performing emulation of wrapper case classes; but how about designing a solution that is tailored to the original motivation – differentiating between type aliases?
object aliases {
// good old aliases
type Id = String
type Password = String
// new "strict" aliases
strict type StrictId = String
strict type StrictPassword = String
}
val id: Id = "a"
val strictId: StrictId = StrictId("b")
// compiles
val s: String = id
val pwd: Password = id
val strictId2: StrictId = strictId
id.toLowerCase()
strictId.toLowerCase() // this is different than `opaque` behavior
// doesn't compile
val s2: String = strictId
val id2: Id = strictId
val strictPwd: StrictPassword = "x"
val strictPwd: StrictPassword = id
val strictPwd: StrictPassword = strictId
// potentially compiles?
val s2: String = strictId.asInstanceOf[String]
val id2: Id = strictId.asInstanceOf[Id]
I don’t have any strong preference to the strict
keyword – it’s just the first thing that popped into mind – but I do believe that opaque
is inadequate for such a feature; in fact, I think it could be useful to introduce both features, where’s opaque
really serves more of a lightweight wrapper, and uses the more class-like syntax accordingly.