> On Dec 31, 2015, at 9:01 AM, Matthew Johnson <[email protected]> wrote:
>
>
>
> Sent from my iPad
>
> On Dec 31, 2015, at 10:09 AM, Dave Abrahams <[email protected]
> <mailto:[email protected]>> wrote:
>
>>
>> -Dave
>>
>>> On Dec 31, 2015, at 7:33 AM, Matthew Johnson via swift-evolution
>>> <[email protected] <mailto:[email protected]>> wrote:
>>>
>>>>
>>>> On Dec 31, 2015, at 5:04 AM, Tino Heth <[email protected] <mailto:[email protected]>>
>>>> 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
>>> [email protected] <mailto:[email protected]>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
-Dave
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution