[swift-evolution] [Proposal Draft] automatic protocol forwarding

Matthew Johnson matthew at anandabits.com
Tue Dec 29 15:45:19 CST 2015


> On Dec 29, 2015, at 3:08 PM, Brent Royal-Gordon <brent at architechies.com> wrote:
> 
>> I have completed a first draft of a proposal to introduce automatic protocol forwarding.  I’m looking forward to feedback from everyone!
> 
> Some things I don't see discussed here:
> 
> * Does it have to be a protocol? Why not also allow the concrete type of the property you're forwarding to? Obviously you couldn't form a subtype relationship (unless you could...), but this might be useful to reduce boilerplate when you're proxying something.

This is addressed in the alternatives considered section.  The short answer is that there the direct interface of the concrete type does not contain sufficient information about potential Self parameters to do this well.  This information does exist in the protocol declarations.  Allowing this information to be specified in concrete interfaces would add enough complexity to the language that I don’t think it is worthwhile.  Joe Groff and I discussed this briefly yesterday: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151228/004660.html <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151228/004660.html>.

What you *can* do is declare a protocol containing the generalized signatures (substituting Self where appropriate) of all of the members of your concrete interface that you wish to be available to forward.  That is a one-time protocol declaration that allows you to forward the concrete interface as many times as you wish.  It seems like a reasonable tradeoff.

> 
> * Why the method-based conversion syntax for return values, rather than something a little more like a property declaration?
> 
> 	var number: Int
> 	forward IntegerType to number {
> 		static return(newValue: Int) {
> 			return NumberWrapper(newValue)
> 		}
> 		return(newValue: Int) {
> 			return NumberWrapper(newValue)
> 		}
> 	}

This is actually a really good idea to consider!  I didn’t consider something like this mostly because I didn’t think of it.  I’m going to seriously consider adopting an approach along these lines.

One possible advantage of the approach I used is that the initializer may already exist for other reasons and you would not need to do any extra work.

A big advantage of this approach is that it would work even when you are forwarding different protocols to more than one member with the same type.

> 
> * If you want to keep the method-based syntax, why use the `init(_:)` initializer instead of one specifically for forwarding, like `init(forwardedReturnValue:)`?

That was a somewhat arbitrary decision I suppose.  I also considered having the compiler look for any initializer accepting the correct type regardless of label.

> 
> * If you want to keep the method-based syntax, why do all forwards, even to different members, share the same transformation method? Wouldn't it be better to have, for instance, `init(returnedNumber:)` and `transformedReturnedNumber(_:)`, so that forwards to other properties could use different logic?

That is a limitation of the approach I used and the proposal disallows you to do such forwarding because of the ambiguity.  I am glad you identified a solution to that!

> 
> * If you want to keep the method-based syntax, would it make sense to instead have an initializer for instance initializers too, and just have it take a second parameter with the instance?
> 
> 	init(forwardedReturnValue: Int) {...}
> 	init(forwardedReturnValue: Int, from: NumberWrapper) {…}

Part of the reason the instance method was used is because sometimes the right thing to do might be to mutate and then return self.  Using an instance method gives you the flexibility to do that if necessary.

> 
> * Does this mean that a `public forward` declaration would forward `internal` members through synthesized `public` interfaces, if the forwarder and forwardee happened to be in the same module?
> 
>> All synthesized members recieve access control modifiers matching the access control modifier applied to the forward declaration.

Yes, if the forwardee had internal visibility and the forwarder was public the forwarder could publicly forward the interface.  This is intentional behavior.  The forwardee may well be an internal implementation detail while the methods of the protocol are part of the public interface of the forwarder.  It is possible to write code that does this manually today.

> * You don't explicitly mention this, but I assume mutating methods work and mutate `self`?

Mutating methods are something I didn’t think about carefully yet.  Thanks for pointing that out!  But generally, yes a forwarding implementation of a mutating method would need to mutate the forwardee which is part of self, thus mutating self.

> 
> -- 
> Brent Royal-Gordon
> Architechies
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151229/2e1fb590/attachment.html>


More information about the swift-evolution mailing list