[swift-users] wishing I could cast (sort of) to protocol, with associated type

Jordan Rose jordan_rose at apple.com
Wed Nov 9 12:36:47 CST 2016


> On Nov 3, 2016, at 11:07, has <hengist.podd at nuggle.uk> wrote:
> 
> Robert Nikander wrote:
>> Cc:"swift-users at swift.org"  <swift-users at swift.org>
>> Subject: Re: [swift-users] wishing I could cast (sort of) to protocol
>> 	with associated type
>> Message-ID:<BF76DEE9-ACA5-4A74-A4F0-FEBB84A422A4 at apple.com>
>> Content-Type: text/plain; charset="utf-8"
>> 
>> The only real way to do this today is to have two layers of protocol:
>> 
>> protocol SpecialControllerBase {
>>   var currentValueBase: SpecialValue? { get }
>> }
>> protocol SpecialController: SpecialControllerBase {
>>   associatedtype SpecialValueType : SpecialValue
>>   var currentValue: SpecialValueType? { get }
>> }
>> extension SpecialController {
>>   var currentValueBase: SpecialValue? { return self.currentValue }
>> }
> 
> One other option may be to put a typealias in an extension instead of declaring an associated type:
> 
> // The almost-a-generic protocol:
> 
> protocol AssProtocol {
>    var xxx: AssType { get }
> }
> 
> extension AssProtocol {
>    typealias AssType = Any
> }
> 
> // My concrete classes:
> 
> class MyClass1: AssProtocol {
>    typealias AssType = Int
>    var xxx: AssProtocol.AssType { return 1 }
> }
> 
> class MyClass2: AssProtocol {
>    typealias AssType = String
>    var xxx: AssProtocol.AssType { return "two" }
> }
> 
> // A generic function that uses the aforementioned protocol:
> 
> func doit<T>(_ v: T) where T: AssProtocol.AssType {
>    print(v, type(of: v))
> }
> 
> // The rare sweet joy that is 0 compiler errors AND 0 runtime crashes:
> 
> let res1 = MyClass1().xxx
> let res2 = MyClass2().xxx
> 
> doit(res1) // 1 Int.Type
> doit(res2) // two String.Type
> 
> 
> Needless to say my head is screeching "probable undefined behavior" even as I type this, so caveat emptor, E&OE, don't blame me when it eats your cat and marries your wife, etc. [1] But it did finally get me out of an unspeakably intractable problem with the Swift type system, thus preserving what precious few last shreds of sanity I still possess. Who knows, now that I only have a myriad of all-but-intractable problems left to work through, one day I might even release!

To see what this is actually doing, try this instead:

func doit<T>(_ v: T) where T: AssProtocol.AssType {
   print(T.self)
}

(and compare it with a true associated type rather than a typealias)

Associated types preserve static type information. The compiler refuses to let you perform operations on protocols with associated types that would throw that information away. You can't get around that check in today's language.

Jordan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20161109/ef91c5e6/attachment.html>


More information about the swift-users mailing list