[swift-evolution] [pitch] Implementation composition

Rien Rien at Balancingrock.nl
Fri Nov 25 10:00:48 CST 2016


I like that.

Have you considered the following?

protocol foobar {
	func foo() …
	func bar() ...
}

class A: foobar { …}

class B: foobar {
	let a = A() implements foobar.foo
	let b = A() implements foobar.bar
}

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl




> On 25 Nov 2016, at 16:33, Jay Abbott via swift-evolution <swift-evolution at swift.org> wrote:
> 
> We already have a great way to compose APIs using protocol composition, and we can supply default implementations for protocol methods, but what if we want to compose implementations from existing types?
> 
> Say I have two disparate protocols:
> 
> protocol A 
> {
>     
> func methodA1()
> 
>     
> func methodA2()
> 
> }
> 
> protocol B 
> {
>     
> func methodB1()
> 
>     
> func methodB2()
> 
> }
> 
> And I also have a selection of classes that implement them, but let’s just consider two:
> 
> class ImplementsA : A 
> {
>     
> func methodA1() 
> {
>         
> print("A1"
> )
>     }
>     
> func methodA2() 
> {
>         
> print("A2"
> )
>     }
> }
> 
> class ImplementsB : B 
> {
>     
> func methodB1() 
> {
>         
> print("B1"
> )
>     }
>     
> func methodB2() 
> {
>         
> print("B2"
> )
>     }
> }
> 
> And I have a composed interface:
> 
> typealias Useful = A & B
> Now I want to implement a Useful class by composing it from the two chosen implementations of A and B:
> 
> class MyClass : Useful 
> {
>     private 
> let a = ImplementsA
> ()
>     private 
> let b = ImplementsB
> ()
> 
>     public 
> func methodA1() 
> {
>         a.methodA1()
>     }
>     public 
> func methodA2() 
> {
>         a.methodA2()
>     }
>     public 
> func methodB1() 
> {
>         b.methodB1()
>     }
>     public 
> func methodB2() 
> {
>         b.methodB2()
>         
> // I want this to do what 'b' does, plus some
> 
>         
> // extra work in MyClass implementations of B
> 
>         
> print("Extra"
> )
>     }
> }
> 
> Not too bad - but that could get pretty tedious if I had 5 protocols to implement with 5 methods each. Much nicer would be:
> 
> class MyClass : Useful 
> {
>     private 
> let a = ImplementsA() implements A
> 
>     private 
> let b = ImplementsB() implements B
> 
> 
>     public 
> func methodB2() 
> {
>         b.methodB2()
>         
> // I want this to do whatever 'b' does, plus some
> 
>         
> // extra work in MyClass implementations of B
> 
>         
> print("Extra"
> )
>     }
> }
> 
> The idea is that implements SomeProtocol after a member variable will synthesize all the methods that aren’t explicitly implemented from SomeProtcol by forwarding the call to that member. Or something more efficient if possible.
> 
> You could also implement protocols using other classes that only partially implement them:
> 
> class PartlyImplementsB 
> {
>     
> func methodB1() 
> {
>         
> print("B1"
> )
>     }
> }
> 
> class MyClass : Useful 
> {
>     private 
> let a = ImplementsA() implements A
> 
>     private 
> let b = PartlyImplementsB() implements B
> 
> 
>     public 
> func methodB2() 
> {
>         
> print("I have to implement this because `b` does not."
> )
>     }
> }
> 
> The way this would work is find the intersection between all methods in the protocol and all methods in the implementing member, then subtract all methods already explicitly implemented in the class, and synthesize those. That way if you had another class AlmostImplementsB that implements methodB2 you could simply do:
> 
>     private let a = ImplementsA() implements A
> 
>     private 
> let b1 = PartlyImplementsB() implements B
> 
>     private 
> let b2 = AlmostImplementsB() implements B
> However, if the synthesis process finds that it’s synthesizing a method twice, for example in this case…
> 
> protocol C 
> {
>     
> func methodC1()
> 
>     
> func methodC2()
> 
>     
> func methodC3()
> 
> }
> 
> class PartlyImplementsC 
> {
>     
> func methodC1() 
> {
>         
> print("C1(partly)"
> )
>     }
>     
> func methodC2() 
> {
>         
> print("C2(partly)"
> )
>     }
> }
> 
> class AlmostImplementsC 
> {
>     
> func methodC2() 
> {
>         
> print("C2(almost)"
> )
>     }
>     
> func methodC3() 
> {
>         
> print("C3(almost)"
> )
>     }
> }
> 
> class MyClass : C 
> {
>     private 
> let cPartly = PartlyImplementsC() implements C
> 
>     private 
> let cAlmost = AlmostImplementsC() implements C
> 
> }
> 
> …then the compiler would emit an error and you would have to explicitly implement methodC2 to prevent it from being double-synthesized. You could of course have your own custom implementation or choose which member to call as your explicit implementation.
> 
> Regarding access: I think it would implement them as public, as this seems obvious for a protocol, but I guess there’s a possibility you might want them to be internal, so perhaps implements(internal) or implements(public) would be better. Or perhaps someone can think of a better word because in the partial case it is a little confusing - is there a single word that means use-to-implement ?
> 
> Regarding value-types: I haven’t thought deeply about this for non-class types, but it can probably work the same for those too.
> 
> Anyway, this could be used to provide a variety of implementations for protocols, composed of different combinations of partial implementations, then use those complete implementations to compose your larger/complex types with the minimum of boilerplate forwarding code.
> 
> Thoughts?
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list