> 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

Reply via email to