In the following code, I want to test if x
is a SpecialController
. If it is, I want to get the currentValue
as a SpecialValue
. How do you do this? If not with a cast, then some other technique.
The last line there won't compile. There error is: Protocol "SpecialController" can only be used as a generic constraint because it has Self or associated type requirements.
protocol SpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
...
var x: AnyObject = ...
if let sc = x as? SpecialController { // does not compile
Unfortunately, Swift doesn't currently support the use of protocols with associated types as actual types. This however is technically possible for the compiler to do; and it may well be implemented in a future version of the language.
A simple solution in your case is to define a 'shadow protocol' that
SpecialController
derives from, and allows you to accesscurrentValue
through a protocol requirement that type erases it:[Edited to fix:
: SpecialValue
, not= SpecialValue
]This is not possible.
SpecialValueController
is an "incomplete type" conceptually so the compiler cannot know.SpecialValueType
, although it is constrained bySpecialValue
, it is not known until it is determined by any adopting class. So it is a really placeholder with inadequate information.as?
-ness cannot be checked.You could have a base class that adopts
SpecialController
with a concrete type forSpecialValueController
, and have multiple child classes that inherit from the adopting class, if you're still seeking a degree of polymorphism.This doesn't work because
SpecialController
isn't a single type. You can think of associated types as a kind of generics. ASpecialController
with itsSpecialValueType
being anInt
is a completely different type from aSpecialController
with itsSpecialValueType
being anString
, just like howOptional<Int>
is a completely different type fromOptional<String>
.Because of this, it doesn't make any sense to cast to
SpecialValueType
, because that would gloss over the associated type, and allow you to use (for example) aSpecialController
with itsSpecialValueType
being anInt
where aSpecialController
with itsSpecialValueType
being aString
is expected.As compiler suggests, the only way
SpecialController
can be used is as a generic constraint. You can have a function that's generic overT
, with the constraint thatT
must be aSpecialController
. The domain ofT
now spans all the various concrete types ofSpecialController
, such as one with anInt
associated type, and one with aString
. For each possible associated type, there's a distinctSpecialController
, and by extension, a distinctT
.To draw out the
Optional<T>
analogy further. Imagine if what you're trying to do was possible. It would be much like this: