[swift-evolution] [Pitch] Nested types in protocols (and nesting protocols in types)

Karl razielim at gmail.com
Mon Oct 24 17:06:36 CDT 2016


> On 24 Oct 2016, at 20:23, Jonathan Hull via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> 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.
>> Alternatively, what if (1) outer types aren’t capture unless they’re referenced, and (2) nesting is only illegal if there’s a capture?
> I was just about to write something similar, but Paul said it better.
> 
> Why don’t we allow everything to be nested in everything for namespacing purposes (which is most of why I want it), but forbid references to generic or associated types from the nested type?  Then, as the generics manifesto gets implemented, we can start allowing certain generics to be referenced over time as they start to become possible and make sense (but we wouldn’t worry about that yet for this proposal)
> 
> Is there another issue which would keep that simpler version from working?
> 
> Thanks,
> Jon
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

Yeah, that’s why I structured it like that. We can’t represent most of the stuff with captured associated types in the type system right now.

I’ll split it up to include just the simple cases, with some rules:

- Protocols cannot capture generic type parameters
- No nested types can capture associated types

@Slava: Yes, I thought about a system where protocols which capture associated types could only be referred to from a concrete conforming type:

protocol Editor {
    associatedtype Content

    protocol Delegate : class { func contentDidChange(oldContent: Content) }
    var delegate : Delegate? { get, set }
}

class ImageEditor : Editor {
    associatedtype Content = Image
    weak var delegate : Delegate? // type is ImageEditor.Delegate, not Editor.Delegate
}

class ImageEditorController : ImageEditor.Delegate {
    func contentDidChange(oldContent: Image) {
    }
}

class TextEditorController : TextEditor.Delegate {
    func contentDidChange(oldContent: String) {
    }
}

And even though that seems pretty cool and like it adds some value, but it seemed like people would want to be able to express “This is a Delegate for any Editor whose Content is Image” rather than only “This is a Delegate for an ImageEditor”. Perhaps that's something which could live alongside a fully existential-based model (i.e. conforming to Editor.Delegate with an inherited associatedtype “Content”, as in the proposal) until we can do that.

Conversion to generic types is also interesting. I thought about perhaps requiring a shorthand for captured types:

protocol MyProtocol {
    associatedtype ErrorType : Error

    enum NestedType<associatedtype ErrorType> { // binds generic parameter ErrorType to associated type ErrorType
        case success
        case failed(ErrorType)
    }

    func getProgress() -> NestedType  // behind-the-scenes when implemented: func getProgress() -> NestedType<Self.ErrorType>
    func setProgress(_: NestedType)   // behind-the-scenes when implemented: func setProgress<E>(_: NestedType<E>) where E == Self.ErrorType
}

On the one hand, it’s a bit of an awkward cludge to work-around gaps in existential support; on the other hand, automatic bridging between existentials and bound generics might be a good feature anyway, because you know more about the generic type and can optimise more.

- Karl
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161025/5b2292a6/attachment.html>


More information about the swift-evolution mailing list