> On Oct 24, 2016, at 4:43 PM, Slava Pestov <spes...@apple.com> wrote: > > >> 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
Should I take a crack at writing up a proposal for this? Now? After ABI work is done? (Probably the latter “OK if no captures” approach?) Eager to help; don’t want to be in the way. P _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution