[swift-evolution] namespacing protocols to other types

Kelvin Ma kelvin13ma at gmail.com
Fri Dec 29 18:51:27 CST 2017


…all i wanted to do was write Thing:Namespace.Protocol

On Thu, Dec 28, 2017 at 4:43 PM, Adrian Zubarev via swift-evolution <
swift-evolution at swift.org> wrote:

> Well again I don’t think we should disallow capturing the outer generic
> type parameter just because you cannot use the protocol inside the outer
> type atm., you still can add a type-eraser. To be honest such usage of the
> existential is not even a requirement for the outer type. On there other
> hand we might want to set the default for the associated type like I showed
> in my previous message. The nested protocol could serve a completely
> different purpose. Furthermore I still think that Generic<A>.P and
> Generic<B>.P should be distinct protocols just like nested generic and
> non-generic types are within an outer generic type. Sure there could be
> other problems with ambiguity if you think of something like
> GenericViewController<T>.Delegate, but the disambiguation when conforming
> to such protocols requires a different solution and is a well known
> limitation today.
>
> That said you won’t design such nested types anyways if you know the
> existing language limitation. I’d say let’s keep it simple in theory and
> just align the nesting behaviour.
>
> About existentials:
>
> For that scenario I can only speak for myself. I wouldn’t want to allow
> directly the where clause existentials like this. It is far better and
> more readable when we force the where clause on typealiases instead. We
> could lift that restriction later if we’d like to, but not the other way
> around. I think it’s okay if we start with a small restriction first and
> see if it adopts well (this is MHO), because this way it shouldn’t harm
> anybody.
>
>
>
>
> Am 28. Dezember 2017 um 21:51:29, Karl Wagner (razielim at gmail.com)
> schrieb:
>
>
>
> On 28. Dec 2017, at 12:34, Adrian Zubarev <adrian.zubarev at devandartist.com>
> wrote:
>
> I disagree with some of your points. Do begin with, I don’t think we
> should disallow capturing the generic type parameter, because I think there
> might be a good way to prevent parameterization of nested protocols.
>
> To me this only feels like a natural consequence of nesting protocols
> anyways. To achieve this we have to provide an explicit associated type
> which will have a default type that refers to the captured outer generic
> type parameter. At this point we discover another issue that we cannot
> disambiguate generic type parameter like associated types yet and would be
> forced to name the associated type of the protocol differently.
>
> struct Generic<T> {
>   protocol P {
>     associatedtype R = T
>     func f() -> R
>   }
> }
>
> As you can see I didn’t include the variable in this example, because
> existential are orthogonal this issue. David Hart and I still want to write
> a proposal to allow the where clause on typealiases - maybe after the
> forum officially launches.
>
> Above I said that there is an issue and provided an example that would
> solve that issue with todays syntax, but I’d rather expand this idea.
> Consider this syntax of a generic type and a protocol with an associated
> type.
>
> protocol Proto {
>   associatedtype Element
> }
>
> Proto.Element // This is an error like this, but it's still allowed in a generic context
>
> func function<P : Proto>(_: P) where P.Element == Int {}
>
> protocol OtherProto : Proto where Element == Int {}
>
> struct Test<Element> {}
>
> extension Test where Element == Int {}
>
> Test.Element // Can/should we allow this?
>
> If we could allow this in Swift then the above example with the nested
> protocol could be disambiguated nicely.
>
> struct Generic<T> {
>   protocol P {
>     associatedtype T = Generic.T
>     func f() -> T
>   }
> }
>
> Remember that Generic.T is only the default for P.T if you don’t set it
> yourself but when you conform or use that that protocol (in a generic
> context) you can still set it differntly.
>
> This consequence disallows protocol parameterization through nesting in a
> generic types, but still behaves very similar to nested generic types:
>
> struct Test<T> {
>   struct NonGeneric {
>     var t: T
>   }
>
>   struct Generic<R> {
>     var t: T
>     var r: R
>   }
> }
>
> _ = Test<String>.NonGeneric(t: "😎")
> _ = Test<String>.Generic<Int>(t: "🤓", r: 42)
>
> ——
>
>
> Yeah, that’s all well and good. I don’t think we should parameterise
> protocols either; it feels like Swift hasn’t been designed with those in
> mind, and that’s fine. You would get in to all kinds of horrible conflicts
> if you tried to conform to both Generic<Int>.P and Generic<String>.P,
> because most functions would have the same signature but possibly very
> different implementations. You would likely end up having to separate the
> conformances by using a wrapper struct — in which case, why not just make
> them the same protocol and have the existing duplicate-conformance rules
> take care of it?
>
> An earlier version of the proposal included something like you describe.
> Basically, Generic<Int>.P and Generic<String>.P would be the same protocol.
> They would have an associated type to represent the parameter from
> Generic<T>, and within Generic<T>, all references to P would be implicitly
> constrained so that P.T == Self.T. You would write conformances to
> “Generic.P” with a constraint for T, as you do today.
>
> And for the existential variable inside Genric it really should be
> something like this (when the where clause is allowed and if we can refer
> differently to generic type parameters as well):
>
> struct Generic<T> {
>>     typealias PConstrainedByT = P where T == Self.T
>     var object: PConstrainedByT
> }
>
>
> If we have that ability, then we can totally do capturing. Forgive me, but
> I understand that as pretty-much the same as generalised existentials
> (without local type binding).
> If I can write the type of object as an existential of (generic protocol +
> constraints) via a typealias, then surely I must also be able to do it
> directly? So I could also write:
>
> struct Generic<T> {
>     var object: P where T == Self.T
> }
>
> Anyway, I thought that was not on the table, and in any case I’m convinced
> that it should be a separate proposal. This gets to the heart of the
> interaction between generic types and protocols, and we all know it’s not
> always a smooth transition (hello AnyCollection, AnyHashable, etc...). We
> can cover the common cases (i.e. the Apple frameworks) without requiring
> capturing - especially since it’s apparently not too difficult to implement
> - and build from there.
>
> - Karl
>
>
>
>
> Am 27. Dezember 2017 um 19:53:36, Karl Wagner via swift-evolution (
> swift-evolution at swift.org) schrieb:
>
> Yeah I wrote that proposal. I eventually stripped it down to just disallow
> all capturing, but it was still not selected by the core team for review
> ¯\_(ツ)_/¯
>
> As for capturing semantics, once you start working through use-cases, it’s
> becomes clear that it's going to require generalised existentials.
> Otherwise, how would you use a Generic<T>.P?
>
> struct Generic<T> {
>     protocol P { func f() -> T }
>
>     var object: P // uh-oh! ‘Generic protocol can only be used as a
> generic parameter constraint'
> }
>
> So, you would need to add a generic parameter to actually *use* P from
> within Generic<T>, which of course limits you to a single concrete type of
> P:
>
> struct Generic<T, TypeOfP> where TypeOfP: Self.P {      // Could this even
> work? What if P captures TypeOfP?
>     protocol P { /* … */ }
>     var object: TypeOfP
> }
>
> Which is just yucky.
>
> Ideally, the type of ‘object’ should be ‘Any<P where P.T == T>’, to
> express that it can be any conforming type with the appropriate
> constraints. You wouldn’t need to write that all out; we could infer that
> capturing is equivalent to a same-type constraint (or perhaps one of these
> “generalised supertype constraints” that were pitched recently). But we
> can’t express those kinds of existentials everywhere in the type-system
> today, so most examples of capturing fall down pretty quickly.
>
> - Karl
>
> On 25. Dec 2017, at 03:56, Slava Pestov via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> There was a proposal to allow protocols to be nested inside types at one
> point but it didn’t move forward.
>
> Basically, if the outer type is a non-generic class, struct or enum,
> there’s no conceptual difficulty at all.
>
> If the outer type is a generic type or another protocol, you have a
> problem where the inner protocol can reference generic parameters or
> associated types of the outer type. This would either have to be banned, or
> we would need to come up with coherent semantics for it:
>
> struct Generic<T> {
>  protocol P {
>    func f() -> T
>  }
> }
>
> struct Conforms : Generic<Int>.P {
>  func f() -> Int { … } // Like this?
> }
>
> let c = Conforms()
> c is Generic<String>.P // is this false? Ie, are Generic<Int>.P and
> Generic<String>.P different protocols?
>
> Slava
>
> On Dec 24, 2017, at 6:53 PM, Kelvin Ma via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> is there a reason why it’s not allowed to nest a protocol declaration
> inside another type?
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> 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/20171229/f9437c3c/attachment.html>


More information about the swift-evolution mailing list