Hi Kevin,

Thanks for taking time to look at the proposal.

The technique you show here is not bad, but it has several deficiencies IMO 
which are addressed by the solution in the proposal.

1. Forwarding should be an implementation detail, not exposed as it is with 
this method.
2. As such, the getter for the forwardee is visible.  The forwardee is an 
implementation detail that should not be visible in most cases.
3. There is no way to specify access control for the synthesized methods and if 
there were it would be coupled to the access control of the conformance.
4. You can't forward to a type that doesn't conform to the protocol.  This is 
particularly important for existential forwardees (at least until they conform 
to their protocol).
5. A type that can't conform to the protocol can't forward an implementation of 
the members of the protocol.  Specifically, non-final classes cannot 
automatically forward a group of methods to an implementer.
6. This solution does not lay the foundation for a newtype feature. It would be 
possible to have a specialized newtype feature, but why not build it on top of 
a more general forwarding feature?

You may be right that many protocols are not amenable to forwarding.  The 
motivation for this proposal is that it enables delegation-based designs to be 
implemented succinctly.  In that use case the protocols will be designed 
alongside concrete implementations and types that forward to them.  A secondary 
motivation for this proposal is to lay a foundation for a newtype feature.  In 
that case the protocols to be forwarded would be specifically designed to 
represent the portion of the interface of the wrapped type which should be 
visible to users of the newtype.

I hope these points might be enough to convince you that it is worth a closer 
look.

Matthew

> On Dec 29, 2015, at 2:06 PM, Kevin Ballard via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> I briefly skimmed your proposal, so I apologize if you already addressed 
> this, but it occurs to me that we could support automatic protocol forwarding 
> today on a per-protocol basis simply by declaring a separate protocol that 
> provides default implementations doing the forwarding. Handling of Self 
> return types can then be done by adding a required initializer (or just not 
> implementing that method, so the concrete type is forced to deal with it even 
> though everything else is forwarded).
>  
> For example, if I want to automatically forward SequenceType to a member, I 
> can do something like
>  
> protocol SequenceTypeForwarder : SequenceType {
>     typealias ForwardedSequenceType : SequenceType
> 
>     var forwardedSequence : ForwardedSequenceType { get }
> }
> 
> extension SequenceTypeForwarder {
>     func generate() -> ForwardedSequenceType.Generator {
>         return forwardedSequence.generate()
>     }
> 
>     func underestimateCount() -> Int {
>         return forwardedSequence.underestimateCount()
>     }
> 
>     func map<T>(@noescape transform: 
> (ForwardedSequenceType.Generator.Element) throws -> T) rethrows -> [T] {
>         return try forwardedSequence.map(transform)
>     }
> 
>     func filter(@noescape includeElement: 
> (ForwardedSequenceType.Generator.Element) throws -> Bool) rethrows -> 
> [ForwardedSequenceType.Generator.Element] {
>         return try forwardedSequence.filter(includeElement)
>     }
> 
>     func forEach(@noescape body: (ForwardedSequenceType.Generator.Element) 
> throws -> Void) rethrows {
>         return try forwardedSequence.forEach(body)
>     }
> 
>     func dropFirst(n: Int) -> ForwardedSequenceType.SubSequence {
>         return forwardedSequence.dropFirst(n)
>     }
> 
>     func dropLast(n: Int) -> ForwardedSequenceType.SubSequence {
>         return forwardedSequence.dropLast(n)
>     }
> 
>     func prefix(maxLength: Int) -> ForwardedSequenceType.SubSequence {
>         return forwardedSequence.prefix(maxLength)
>     }
> 
>     func suffix(maxLength: Int) -> ForwardedSequenceType.SubSequence {
>         return forwardedSequence.suffix(maxLength)
>     }
> 
>     func split(maxSplit: Int, allowEmptySlices: Bool, @noescape isSeparator: 
> (ForwardedSequenceType.Generator.Element) throws -> Bool) rethrows -> 
> [ForwardedSequenceType.SubSequence] {
>         return try forwardedSequence.split(maxSplit, allowEmptySlices: 
> allowEmptySlices, isSeparator: isSeparator)
>     }
> }
>  
> With this protocol declared, I can then say something like
>  
> struct Foo {
>     var ary: [Int]
> }
> 
> extension Foo : SequenceTypeForwarder {
>     var forwardedSequence: [Int] { return ary }
> }
>  
> and my struct Foo now automatically implements SequenceType by forwarding to 
> its variable `ary`.
>  
> The downside to this is it needs to be manually declared for each protocol. 
> But I wager that most protocols actually aren't really amenable to forwarding 
> anyway.
>  
> -Kevin Ballard
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to