[swift-evolution] [Idea] Generic associated types

John McCall rjmccall at apple.com
Mon Mar 13 11:50:55 CDT 2017


> On Mar 12, 2017, at 5:00 PM, Matthew Johnson via swift-evolution <swift-evolution at swift.org> wrote:
>> On Mar 12, 2017, at 3:23 PM, Karl Wagner <razielim at gmail.com <mailto:razielim at gmail.com>> wrote:
>> 
>> 
>>> On 12 Mar 2017, at 14:32, Matthew Johnson <matthew at anandabits.com <mailto:matthew at anandabits.com>> wrote:
>>> 
>>> This is a really important feature IMO, but as others have pointed out it basically amounts to higher-kinded types.  I would love to be wrong about this but I am reasonably sure this is out of scope for Swift 4 (otherwise I would be working on a proposal already).
>>> 
>>> Sent from my iPad
>>> 
>> 
>> I’m not an expert on this stuff, but are they still higher-kinded types if we don’t express a relationship between Self and the associated type? I don’t think it’s quite the same conceptual leap as HKT.
> 
> I’m no expert either but it sure seems to me like it enables the things usually discussed in the context of higher-kinder types.  Maybe someone from the core team can comment on whether there is a meaningful difference

Yes, it's a way of getting some of the behavior of higher-kinded types.  Kind of a well-known trick in a number of languages.  It's significantly simpler to handle in the type system because the higher-kinded entities stay "second class" — you don't necessarily have to deal with, say, higher-kinded type variables in the constraint solver or in type inference.  Of course, that limits some of the code you can write, or at least the simplicity of that code.

> and whether this is something that could fit into Swift 4.

No.

John.

> 
>> 
>> Consider that every associated type must be backed by a typealias (explicit or inferred) in the conforming type. We can already have generic typealiases. This would be a more targeted thing which required those associatedtype-implementing-typealiases to contain generic parameters. It would also extend the constraints from SE-0142 to allow constraints to refer to those parameters and bind them to other associated types.
>> 
>> The workaround is basically to erase and dynamic-cast your way out:
> 
> Yes, there are workarounds, none of which are desirable.  
> 
> I ran into a case last year where there was a significant performance impact caused by the need to perform type erasure as a workaround.  The type erasing wrapper required an allocation and type information that could have been used by the optimizer was lost.  This was frustrating and convinced me that we definitely need HKT in Swift eventually.  There are very useful generic libraries that cannot be implemented efficiently without them.
> 
> 
>> 
>>       //NOTE: dynamic type of ScanPromise.Result *must* be same as closure result. No static enforcement though :(
>> 
>> extension Scanner where ScanPromise.Result == Any? {
>>     func scan<T>(from f: Offset, until u: (Offset, Item) -> T?) -> T? {
>>         return withoutActuallyEscaping(u) { _u -> T? in
>>           return promiseScan(from: f, until: _u).await() as? T // downcast from Any? to T?
>>         }
>>     }
>> }
>> 
>> class MyPromise<R>: Promise {
>>     typealias Result = R?
>>     let offset: Offset
>>     let block: (Offset, Item) -> R?
>> }
>> 
>> class MyScanner: Scanner {
>>     typealias ScanPromise = MyPromise<Any> // want this to be “typealias ScanPromise<X> = MyPromise<X>"
>> 
>>     func promiseScan<T>(from: Offset, until: @escaping (Offset, Item) -> T?) -> ScanPromise {
>>         return MyPromise(offset: from, block: until) // upcast from T? to Any?
>>     }
>> }
>> 
>> - Karl
>> 
>>> On Mar 11, 2017, at 11:49 PM, Karl Wagner via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>>> I have a model like this:
>>>> 
>>>> protocol Promise {
>>>>     associatedtype Result
>>>> }
>>>> 
>>>> protocol Scanner {
>>>>     associatedtype ScanPromise: Promise
>>>> 
>>>>     func promiseScan<T>(from: Offset, until: (Offset, Item) -> T?) -> ScanPromise // where Result == T?
>>>> }
>>>> 
>>>> The thing that I’m trying to express is: whichever type implements the associated type ‘ScanPromise’ must be generic, and that parameter must be its result (i.e. something it got as a result of calling the “until” closure).
>>>> 
>>>> Even with SE-0142, this kind of constraint would not be possible. What I would like to write is something like this:
>>>> 
>>>> protocol Promise {
>>>>     associatedtype Result
>>>> }
>>>> 
>>>> protocol Scanner {
>>>>     associatedtype ScanPromise<T>: Promise // now generic. [SE-0142]: where Result == T
>>>> 
>>>>     func promiseScan<T>(from: Offset, until: (Offset, Item) -> T?) -> ScanPromise<T>
>>>> }
>>>> 
>>>> Thoughts?
>>>> 
>>>> - Karl
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170313/299ff5ec/attachment.html>


More information about the swift-evolution mailing list