> On Oct 24, 2016, at 8:12 AM, Paul Cantrell <cantr...@pobox.com> wrote:
> 
> 
>> On Oct 24, 2016, at 5:09 AM, Slava Pestov via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> However protocols nested inside types and types nested inside protocols is 
>> still not supported, because protocols introduce a separate series of issues 
>> involving associated types and the ’Self’ type.
>> 
>> The hard part of getting nested generics right is what to do if a nested 
>> type ‘captures’ generic parameters of the outer type. For non-protocol 
>> types, the behavior here is pretty straightforward.
>> 
>> If we allow protocols to be nested inside other types, we have to decide 
>> what to do if the protocol ‘closes over’ generic parameters of the outer 
>> type. For example,
>> 
>> struct A<T> {
>>  protocol P {
>>    func requirement() -> T
>>  }
>> }
>> 
>> Presumably A<Int>.P and A<String>.P are distinct types, and A.P has a hidden 
>> associated type corresponding to the type parameter ’T’?
>> 
>> The other case is problematic too — the nested type might refer to an 
>> associated type of the outer protocol:
>> 
>> protocol P {
>>  associatedtype A
>> 
>>  struct T {
>>    var value: A
>>  }
>> }
>> 
>> Now writing P.T does not make sense, for the same reason that we cannot form 
>> an existential of type P.A. We could prohibit references to outer associated 
>> types of this form, or we could figure out some way to give it a meaning. If 
>> C is a concrete type conforming to P, then certainly C.T makes sense, for 
>> instance. Internally, the nested type A.T could have a hidden ‘Self’ generic 
>> type parameter, so that writing C.T is really the same as P.T<C>.
>> 
>> Protocols nested inside protocols also have the same issue.
> 
> FWIW, in almost all the situations where I’ve wanted to nest types inside 
> protocols and generic types, it’s only as a namespacing convenience. Most 
> often, it’s an enum type that’s used only by a single method, and having it 
> at the top of the module namespace adds clutter.
> 
> Here’s a real life example pared down. I wish I could do this:
> 
>    public struct ResponseContentTransformer<InputContentType, 
> OutputContentType>: ResponseTransformer {
> 
>      public init(onInputTypeMismatch mismatchAction: InputTypeMismatchAction 
> = .error) {
>        ...
>      }
> 
>      public enum InputTypeMismatchAction {  // Does not depend on generic 
> types above
>        case error
>        case skip
>        case skipIfOutputTypeMatches
>      }
> 
>    }
> 
> InputTypeMismatchAction is tightly associated with 
> ResponseContentTransformer, and is confusing as a top-level type.
> 
> What do you think about providing a “no captures” modifier for nested types — 
> like static inner classes in Java? Then Swift could provide the namespace 
> nesting I wish for this without having to resolve the trickier type capture 
> questions yet.
> 
> Alternatively, what if (1) outer types aren’t capture unless they’re 
> referenced, and (2) nesting is only illegal if there’s a capture? Then my 
> code above would compile, as would this:
> 
>    public struct S<T> {
>      public enum Foo {
>        case yin
>        case yang
>      }
>    }
> 
> …but this wouldn’t:
> 
>    public struct S<T> {
>      public enum Foo {
>        case yin(thing: T)  // capture of T illegal (for now)
>        case yang
>      }
>    }
> 
> Either of these approaches would allow hygienic namespacing now while leaving 
> the door open to outer type capture in the future.

Yeah, this makes sense for a first cut at this feature.

Slava

> 
> Cheers,
> 
> Paul
> 
> 
> 

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to