> 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