TypeErasure is certainly possible right now, but it is a pain in the butt, and difficult to implement correctly. Once you have the correct boilerplate written, it makes it difficult to change things because you have to change them in 3~4 different places. It seems to me that the compiler could write these thunks pretty easily... we just need some syntax to be able to think of the erased versions as a different type from the un-erased versions.
There are two kinds of type erasure to consider:
- Type Erasing generics from Structs/Types
- Type Erasing associatedtypes from Protocols
Let's start with types:
Let's say we have a struct:
struct Foo<T,U> {
let t:T
let u:U
}
The syntax I would like to see is allowing _
to erase any particular generic. So Foo<_,U>
would generate a thunk with the following:
struct Foo<_,U> {
let t:Any //This would still have any restrictions that T had on it (e.g. hashable)
let u:U
}
To get the original struct back you would use as?
or as!
:
let erasedFoo:Foo<_,_> = myFoo
let foo:Foo<T,U>? = erasedFoo as? Foo<T,U>
Next, let's look at protocols. There are a couple of ways we could go here.
I really like the idea of having an Any<Protocol>
syntax which would allow you to refer to and store protocols with self and associatedtype requirements.
The other option would be to allow a where clause in the definition to either define or erase the problematic requirements. For example, if we have a protocol Bar:
protocol Bar {
associatedtype Element
var element:Element {get}
}
If we want to use this as a variable we can't:
var bar:Bar //Error: Can only be used as a constraint because of associated type
We could allow a where clause to define away the ambiguity:
var bar:Bar where Bar.Element == Int
Or if we want to type erase Element, we could use _
again:
var bar:Bar where Bar.Element == _
You could also type alias it to avoid writing everything over and over:
typealias AnyBar = Bar where Bar.Element = _
var bar:AnyBar
Again, we would want to be able to recover the true type with as?
and as!
Anyway, I am sure I have forgotten something (feel free to correct me), but I wanted to get a discussion started since I run into this all the time. Seriously. It is my #1 frustration with Swift...