Hello,
Here is the proposal:
Do not allow a typealias to be assigned to another (even if it’s the same type at runtime). doing this is forbidden by compiler (resulting a compilation error).
the following example will be used:
class RealRuntimeType
typealias TypeAlias = RealRuntimeType
typealias TypeAliasBis = RealRuntimeType
note: they are typealias, this is all compilation checks & only RealRuntimeType
will exist at runtime.
Why ?
This allow typealias to be use to type things in a very light way (from code point of view & runtime).
assignation
The global idea is too allow transformation (that will be lose at runtime) from an alias type to and from its real type.
so we can assign:
- a
RealRuntimeType
to aTypeAlias
&TypeAliasBis
- a
TypeAlias
to aRealRuntimeType
- a
TypeAliasBis
to aRealRuntimeType
example:
class RealRuntimeType
typealias TypeAlias = RealRuntimeType
typealias TypeAliasBis = RealRuntimeType
fun main(args: Array<String>) {
val aTypeAlias: TypeAlias = RealRuntimeType() //ok
val aTypeAliasBis: TypeAliasBis = RealRuntimeType() //ok
val anotherTypeAliasBis: TypeAliasBis = aTypeAlias //compile error : "TypeAlias cannot be assigned to TypeAliasBis"
afunction(aTypeAlias) //compile error : "type mismatched..."
}
fun afunction(typeAliasBis: TypeAliasBis ) = ...
as
& is
operator
this is just compile erorrs, at runtime we only have RealRuntimeType
so any dynamic operator (as
, is
) is running with RealRuntimeType
.
var aTypeAlias: TypeAlias = RealRuntimeType() //ok
var aTypeAliasBis: TypeAliasBis = aTypeAlias as RealRuntimeType //ok
this also means that any dynamic operation (like as
& is
) are not subject to the compiler checkings in this proposal):
aTypeAliasBis = aTypeAlias as TypeAliasBis //ok, at runtime they all are RealRuntimeType
Not been able to write val anotherTypeAliasBis:TypeAliasBis = aTypeAlias
while we can write val anotherTypeAliasBis: TypeAliasBis = aTypeAlias as TypeAliasBis
can be confusing but the code deliberatly use a dynamic operation so its ok.
Same applies to use of is
and smart cast
Back compatibilty
Because this could break existing code it should be done in 2 steps : first generate a warning, then, in a later version, go for the error.
If we really want to assign a typealias to another, just explicitly cast it to the real runtime type : val y:Y = x as String
What about inline class ?
Inline class are made to add behaviour (you can add methods, implement interface…). They are very powerfull & light at runtime… But we don’t need all this power just to just type things. Moreover inline classes come with drawbacks
from a code point-of-view, if we just want to type thing:
- Inline class are berbose at use : need to call constructor on creation &
.value
on pseudo destructuration (which is a problem mostly in tests). - Inline class are verbose at declaration if we just want to type thing :
inline class X(val value:String)
: the only important information is :X
&String
From a runtime point-iof-view:
- they can be (accidently) boxed
- they cannot be used in generics without boxing
- they have specific behaviour regarding to array
- and so on…
I’m not saying inline class are bad (actually they are insanly powerfull), they are just not intended “just to type thing”.
Variant
Add a soft keyword before typealias to add this behaviour. Example strict typealias Y = String
This could be used as a temporary or definitive variant