> On Dec 31, 2015, at 9:01 AM, Matthew Johnson <matt...@anandabits.com> wrote: > > > > Sent from my iPad > > On Dec 31, 2015, at 10:09 AM, Dave Abrahams <dabrah...@apple.com > <mailto:dabrah...@apple.com>> wrote: > >> >> -Dave >> >>> On Dec 31, 2015, at 7:33 AM, Matthew Johnson via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >>> >>>> >>>> On Dec 31, 2015, at 5:04 AM, Tino Heth <2...@gmx.de <mailto:2...@gmx.de>> >>>> wrote: >>>> >>>> >>>>> I don’t want this thread to get distracted with memberwise initialization >>>> Makes sense in general, but Kotlin solves those problems as a whole, and >>>> the major benefit of their approach is that everything fits together >>>> really fine. >>>> But I'll skip everything that is not related to forwarding. >>>> >>>>> One approach I considered would look like this: >>>>> >>>>> class Forwarder: P { >>>>> // I didn’t like `implements` but didn’t have a better idea before I >>>>> abandoned this approach >>>>> var forwardee: Forwardee implements P >>>>> } >>>> Honestly, I'm can't see the value this discarded variant has for this >>>> discussion… you have to pit your proposal against Kotlin if you really >>>> want to convince anyone of its superiority. >>>> >>>>> With the memberwise initialization proposal you also have the initializer >>>>> synthesized automatically. The only thing it doesn’t do that your Kotlin >>>>> example does is automatically declare conformance. This was an >>>>> intentional design decision because it allows for additional >>>>> expressivity. This is addressed in the alternatives considered section >>>>> of the proposal. >>>> Can you be more precise? Kotlin clearly states what a class is doing in >>>> its first line, with all expressivity that is necessary by practical means. >>> >>> What I mean is this. In the example you gave and the syntax Kotlin uses: >>> >>> classs Forwarder(forwardee: Forwardee): P by forwardee {} >>> >>> Forwarding is coupled to protocol conformance. This means I cannot use >>> forwarding without conforming to the protocol that is forwarded. >>> >>> Here is a quick example using the syntax of my proposal to demonstrate the >>> difference: >>> >>> class Forwarder { >>> let forwardee: Forwardee >>> forward P to forwardee >>> } >>> >>> vs >>> >>> class Forwarder: P { >>> let forwardee: Forwardee >>> forward P to forwardee >>> } >>> >>> In the first example Forwarder does not conform to P. Forwarding is only >>> used to synthesize the members of P. I am greatly expanding the motivation >>> section of the proposal and will have examples showing where this is what >>> you want. The lazy collections section I posted last night includes the >>> first examples where this is the case. >>> >>> In the second example here Forwarder does conform to P. The author of >>> Forwarder has the flexibility to specify whether conformance is desired or >>> not. >> >> There are ways to handle that, including factoring the APIs of interest out >> of P and into a private protocol Q, then declaring the Forwardee’s >> conformance to Q. Now, there’s an expressivity problem with our current >> access control system that you can’t use an internal or private protocol to >> provide public API, but that should be fixed separately. > > I'm not sure where Q comes into play in this specific example. The idea here > is that forwarding implementations of all members of P are synthesized by the > forward declaration. It is left up to Forwarder to decide whether or not to > declare actual conformance to P. I am also confused by "then declaring the > Forwardee’s conformance to Q" because we are discussing Forwarder's > conformance here, not Forwardee’s.
Presumably both ends of the forwarding arrangement would have to conform to the same protocol, no? > What do you have in mind when you mention using a private or internal > protocol to provide public API? It sounds like that might be interesting but > I'm having trouble imagining what the syntax would look like and exactly how > it would work. Is this something that is planned? Not planned, but desired. > What might it look like? Details need to be worked out. One thing we were doing for a while in the stdlib, before the rules got tightened and made it impossible, was struct X : PublicProtocol, PrivateProtocol { ... } extension PublicProtocol where Self : PrivateProtocol { // API that uses only PublicProtocol in its implementation here } > In any case, I don't see why that is related to requiring a Forwarder to > conform to the forwarded protocol. There doesn't appear to me to be a good > reason to require that and there are reasons not to require it. Protocols > enable and drive the forwarding member synthesis mechanism but that mechanism > doesn't need to require or provide conformance. It is a third major way to > use protocols in addition to generic constraints and existential types. Of course I could be wrong, but my instincts tell me that is an unneeded dimension of complexity, which is why I am resisting it. The generic/existential duality is already problematic in some ways, IMO. > >> >>> >>>> >>>>> Another difference that is maybe subtle but I think important is that >>>>> with the approach I considered forwarding is declared in the body of a >>>>> type or extension which emphasizes the fact that forwarding is an >>>>> implementation detail, not something users of the type should be >>>>> concerned with. >>>> But what is the benefit of this emphasis? No solution requires to make the >>>> details visible in the public interface, and the ability to bury an >>>> important thing like protocol conformance somewhere in the class >>>> implementation is no advantage for me. >>> >>> Protocol conformance is not buried in the implementation in my solution. I >>> hope the previous example makes that clear. What is buried in the >>> implementation is the forwarding declaration which causes the compiler to >>> synthesize forwarding member implementations. This synthesis is an >>> implementation detail and should not be visible outside the implementation. >>> >>>> >>>>> This approach was abandoned as it leads to problems in expressivity and >>>>> clarity. Please see alternatives considered for an elaboration of that. >>>>> This is especially true with the new approach to handling Self values >>>>> that Brent suggested. That approach requires additional syntax around >>>>> the forwarding declaration, but adds both clarity and expressiveness. >>>> I think there is little need to worry about expressiveness for a feature >>>> that most potential users will probably never utilize in real code — and I >>>> don't think options like not conforming to a protocol that is forwarded is >>>> a big win here. It looks to me like you are optimizing for very uncommon >>>> cases, and sacrificing ease of use in the situations that are the most >>>> common by far. >>> >>> Like I stated, I am working on adding several examples of how this feature >>> can be used in real code. Please have a look at the lazy collections >>> example I shared last night. This example, as well as at least one other >>> coming examples take advantage of the ability to use forwarding without >>> requiring conformance. >>> >>> As with the memberwise initialization proposal, the syntax you would like >>> to see can easily be added as syntactic sugar on top of the current >>> proposal. I would not support that as I do not like the syntax Kotlin uses >>> for reasons already stated, but that shouldn’t stop you from pursuing a >>> proposal for it. Maybe a lot of people would agree with you and it would >>> be accepted. >>> >>> Matthew >>> >>>> >>>>> It appears to me that you value conciseness very highly. I do value >>>>> conciseness but I also value safety, clarity, and expressiveness. >>>> No, I value elegance and simplicity — they often lead to clarity and >>>> safety. >>>> >>>>>> Why not simply make this feature syntactic sugar and just auto-generate >>>>>> the forwarding methods? >>>>> >>>>> That is exactly what this proposal does. Why do you feel it is not doing >>>>> that? >>>> you're right, guess I mixed up the proposal with something else; so at >>>> least we agree on how it should work ;-) >>>> >>>> I'm not saying Swift has to copy another language, but I doubt that anyone >>>> who knows Kotlin would actually consider to drop their solution in favor >>>> of what is currently discussed... >>>> >>>> Tino >>>> >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> <https://lists.swift.org/mailman/listinfo/swift-evolution> -Dave
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution