this
could be replaced by something else. Having a fake constructor as in your example is confusing – the parameter can not be modified on input, it can not be public, val, var, etc… it shares nothing with an ordinary constructor list other than naming the variable.
this
was the first thing that came to mind.
This construct shares more with object
than traits or classes, so I am not concerned with objections about dissimilarity with trait or class semantics.
Yes, extends
is not the best word. It was an existing keyword, I did not want to make a new one. I guess for
or as
may be more appropriate
opaque Permission as Int
?
No. this
is of type Int
not type Permission
, so no recursion. That may be confusing, maybe a different name should be used, like inner
or wrapped
.
To be honest, I dislike the ‘fake member’ as much as I dislike ‘this’. I am not convinced whether a user supplied name is better than a fixed one either way. Both have advantages and disadvantages.
The scope is far larger than multiversal equality. See the discussion in this thread in the past. I would not want an Akka like send def send(Any: a) = ...
to accept opaque types. Wrap it in a case class, or explicitly unwrap to int. Its not type safe to upcast these. I wouldn’t even want them to work in something like `s"{someOpaque}" unless that opaque explicitly has its own toString.
In short… I don’t think they are true subtypes of Any, because the language relies on runtime information for dispatch in many places (esp. pattern matching and OO polymorphism), and without runtime information they can not conform to the contracts of Any.
Thus, these values are not true subtypes of Any. You have to unpack one to get an Any value out, but can create a List[Permission]
without doing so. Unfortunately, there is no escape from lack of safety, unless you forbid treating the type parameter in List[+A]
covariantly if it is inhabited by an opaque type. There are probably other holes too, especially with union and intersection types. I don’t know what it would look like to try and patch them all or if its possible.
But, if the blatantly obvious passing of an opaque value to its ‘wrapped’ type is blocked, why not any other casting?
val x: Logarithm = ???
// why block this:
def square(d: Double) = d * d
square(x) // can't do it!
// what about this ?
def sneaky(d: AnyVal) = d match { case Double => d * d }
sneaky(d)
// or this?
def sneakyAny(d: Any) = d match { case Double => d * d }
sneakyAny(d)
I don’t understand why its not ok to supply a Logarithm for a Double parameter, but it is OK to substitute it for an Any parameter.
This is a compiler-only type, a user should have to unwrap or convert it before leaving where the compiler can track its type. IMO all the above should be invalid. Its not safe to implicitly erase an opaque type.