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

Adrian Zubarev adrian.zubarev at devandartist.com
Sat Oct 22 03:14:14 CDT 2016


First of all, thank you for writing the formal proposal.

To begin with, I’d like to remember you that type nesting is not only done through nesting types directly in concrete types. A commonly used pattern to reduce clustering is nesting inside extensions:

extension TypeName {
     
    class InnerTypeName { … }
}
Next up:

protocol Outer {
     protocol Inner {
         associatedtype Huh // why would you do this?
     }
}
I disagree with this: why would you want to restrict this?

The Outer protocol might be simple by the inner protocol is not. If you’d move the associatedtype Huh into Outer protocol you’d automatically break the intended simplicity of the Outer protocol.

The following example is kept simple just to show that the outer protocol is in our case intended to be simple where the inner is not.

protocol Building {
     
    protocol Room {

        associatedtype Person
    }

    var numberOfRooms: Int { get }
}

struct Pupil {}
struct Student {}

struct University : Building {
     
    let numberOfRooms: Int = 1000

    struct Room : Building.Room {

        typealias Person = Student
    }
}

struct School : Building {
     
    let numberOfRooms: Int = 100

    struct Room : Building.Room {

        typealias Person = Pupil
    }
}

let buildings: [Building] = [University(), School()] // fine because `Building` is simple
The inner types in this example are different from each other, but this wasn’t the main point anyways.

Unless this restriction would have other technical reasons than “It is hard to think of a valid reason why a nested protocol might want to be more generic than its parent”, I’m against it.

At the very beginning I said that nesting is also done through extensions. Let’s rewrite the above example from your draft that way and see what we good.

protocol Outer {} // Simple

extension Outer {
     
    // Complex
    protocol Inner {
     associatedtype Huh // why would you do this?
  }
}

// new name spacing `Outer.Inner`
From this perspective it’s much clearer now that the Outer protocol type in out case is intended to be simple.

About associatedtypes with extensions:

In Swift 3.0 this code compiles:

public class Class {}

public protocol Outer {
    associatedtype AAA : Class
}

extension Outer {
    public typealias AAA = Int
}
This does mean that the associatedtype is lost in extensions and can be reused as an inner type for nesting. This also means that the inner type wouldn’t be able to capture the associatedtype from the outer type and might be simple.

protocol Outer {

   associatedtype AAA
}

extension Outer {
    protocol Inner {} // Simple because nesting from within extensions seems to ignore the associatedtype from the `Outer` type
}
You can compare this to todays workarounds where you only want to create a nice name space but want to keep the inner type simple.

// Implementation artifact
protocol _Inner {} // simple

// Complex
protocol Outer {
    associatedtype Anything
}

extension Outer {
    typealias Inner = _Inner
}

// Free to use `Outer.Inner`


-- 
Adrian Zubarev
Sent with Airmail

Am 22. Oktober 2016 um 04:18:25, Karl (razielim at gmail.com) schrieb:


On 22 Oct 2016, at 04:12, Karl <raziel.im+swift-evo at gmail.com> wrote:


On 22 Oct 2016, at 04:07, Karl <raziel.im+swift-evo at gmail.com> wrote:


On 22 Oct 2016, at 04:02, Braeden Profile <jhaezhyr12 at gmail.com> wrote:

But what would that mean?  If I reference `ProtocolName.InnerType`, that doesn’t always have meaning.  In fact, if you have two different extensions where AssociatedType equals something else, there’s a type ambiguity from other code.  I suspect it would only work if that InnerType was mandated to be `private`.

You would need a reference to a (ProtocolName where AssociatedType == Int), which you can get either from a `self` inside the extension or from a generic parameter:

struct MyValue<T> : ProtocolName { typealias AssociatedType = T }

let _ = MyValue<Int>().InnerType()

No, wait - sorry, that’s wrong. I got confused for a second. You’re right; it would have to be a private type.

Actually I think I take that back (I was just writing, lots of snippets floating around my head) - ProtocolName is a generic protocol, so types inside of it would become types on the concrete conformers. That’s consistent with the Editor.Delegate example in the draft proposal I linked to.

So MyValue<Int>.InnerType would exist 👍 ProtocolName.InnerType isn’t really very meaningful otherwise.

- Karl




On Oct 17, 2016, at 12:44 PM, Adrian Zubarev via swift-evolution <swift-evolution at swift.org> wrote:

That option should not be disallowed. Here is a simple example you might want to build at some point:

protocol ProtocolName {
      
    associatedtype AssociatedType
}

extension ProtocolName where AssociatedType == Int {
   
    struct InnerType {}
}



-- 
Adrian Zubarev
Sent with Airmail

Am 17. Oktober 2016 um 20:30:58, Karl via swift-evolution (swift-evolution at swift.org) schrieb:

Is your vision that each conforming type would have to provide its own nested type as specified by the protocol?

Or could the protocol itself define a nested type and anything could use it?

protocol FloatingPoint: … {
    enum RoundingRule {
        // Do I put an implementation here?
    }
}

No, types which are defined inside the protocol are implemented there. Providing your own types to satisfy a conformance is what associated types are for.

If you wanted something like that, you could do it with a nested protocol + associated type:

protocol FloatingPoint {

    protocol _RoundingRule { func round(_ : Super) -> Super }
    associatedType RoundingRule : _RoundingRule
}

struct Float : FloatingPoint {

    enum RoundingRule : _RoundingRule {
        func round(_ val: Float) -> Float {
            /* switch self, perform rounding… */ 
        }
    }
}

That brings up an interesting point, though - we would need a way to refer to the outer protocol (I used “Super” here).


_______________________________________________
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/20161022/cda025e6/attachment-0001.html>


More information about the swift-evolution mailing list