[swift-evolution] protocol based invocation forwarding

Matthew Johnson matthew at anandabits.com
Tue Dec 8 16:41:41 CST 2015


Yes, it should be pretty straightforward to handle the wrapping and unwrapping for the single member / newtype case.  Thanks bringing that up.  I will keep that in mind if I get around to writing this proposal before someone else does.

Is a forwarding mechanism like this something that might be considered in the Swift 3 timeframe?

Sent from my iPad

> On Dec 8, 2015, at 2:52 PM, Joe Groff <jgroff at apple.com> wrote:
> 
> 
>> On Dec 8, 2015, at 10:09 AM, Matthew Johnson <matthew at anandabits.com> wrote:
>> 
>> Would it be acceptable to make forwarding of member with Self return types optional for the forwarder (i.e. If the initializer / factory function is not provided the member is not forwarded and must be implemented manually)?
> 
> That's definitely a reasonable answer.
> 
> In my mind, an ideal solution would make it easy to implement 'newtypes' that wrap a type while exposing selected parts of the original type's interface. For example, if you wanted to make strongly-typed units valued as Doubles that still support arithmetic:
> 
> protocol Addable { func + (_: Self, _: Self) -> Self }
> 
> struct Weight: Addable {
>   var value: Double implements Addable
> }
> struct Distance: Addable {
>   var value: Double implements Addable
> }
> 
> it'd be nice if the unwrapping and wrapping defaulted to something sensible.
> 
> -Joe
> 
>> Sent from my iPad
>> 
>>> On Dec 8, 2015, at 11:53 AM, Joe Groff via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>> It'd definitely be awesome to support forwarding protocol conformances. One thing a forwarding design needs to consider is how to handle `Self` requirements in the forwarded protocol. If the protocol requirements consume `Self` types, you need a conversion operation to go from the forwarder to the forwardee type, such as the getter for the forwardee property.
>>> If there are any requirements that return `Self` you'd need to additionally provide an initializer or factory function capable of building a new instance of the forwarder type from the forwardee.
>>> 
>>> -Joe
>>> 
>>>> On Dec 7, 2015, at 1:33 PM, David Owens II via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 
>>>> Often it is the case where one might want to implement a type that provides an interface but has inner components that actually handle the implementation. In those cases, we end up with a lot of boiler-plate code that simply turns around and invokes the on the instance.
>>>> 
>>>> Let’s take the example of class clusters:
>>>> 
>>>> private protocol _Cluster {
>>>>     func description() -> String
>>>> }
>>>> 
>>>> class Cluster: _Cluster {
>>>>     
>>>>     private var _instance: _Cluster
>>>>     
>>>>     init(name: String) {
>>>>         _instance = _ClusterString(name: name)
>>>>     }
>>>>     
>>>>     init(value: Int) {
>>>>         _instance = _ClusterValue(value: value)
>>>>     }
>>>>     
>>>>     // this is pure boiler-plate
>>>>     func description() -> String {
>>>>         return _instance.description()
>>>>     }
>>>> }
>>>> 
>>>> private class _ClusterString: _Cluster {
>>>>     private var name: String
>>>>     init(name: String) { self.name = name }
>>>>     func description() -> String {
>>>>         return "_ClusterString: \(name)"
>>>>     }
>>>> }
>>>> 
>>>> private class _ClusterValue: _Cluster {
>>>>     private var value: Int
>>>>     init(value: Int) { self.value = value }
>>>>     func description() -> String {
>>>>         return "_ClusterValue: \(value)"
>>>>     }
>>>> }
>>>> 
>>>> let s = Cluster(name: "a string")
>>>> s.description()
>>>> 
>>>> let v = Cluster(value: 12)
>>>> v.description()
>>>> 
>>>> 
>>>> Now, it would be nice to not have to have to implement the boiler-plate (this example only has a single method, so the savings seem minimal).
>>>> 
>>>> class Cluster: _Cluster {
>>>>     @forward(_Cluster, _instance)
>>>> 
>>>>     private var _instance: _Cluster
>>>>     
>>>>     init(name: String) {
>>>>         _instance = _ClusterString(name: name)
>>>>     }
>>>>     
>>>>     init(value: Int) {
>>>>         _instance = _ClusterValue(value: value)
>>>>     }
>>>> }
>>>> 
>>>> The @forward(protocol, instance) attribute lets the compiler know that the _Cluster protocol should be forwarded to the _instance value. The compiler would then generate all of the implementation stubs. Refactoring is also made simple as API changes to _Cluster do not need to be manually reflected on the type.
>>>> 
>>>> Another way to solve this problem is with a sufficiently advanced macro system. But that is out-of-scope for v3. However, this seems like it could be a straight-forward enough implementation to support in the mean-time, with an easy path for removal/update if it were to be replaced by a macro system.
>>>> 
>>>> -David
>>>> 
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151208/20a75dc4/attachment.html>


More information about the swift-evolution mailing list