Re: [swift-evolution] [pitch] Implementation composition
> On Nov 25, 2016, at 12:06 PM, Nevin Brackett-Rozinsky via swift-evolution >wrote: > > Protocol forwarding was discussed on-list near the end of 2015 in the thread > “[swift-evolution] [Proposal Draft] automatic protocol forwarding”. Feedback > was generally positive, though there were disagreements about whether the > forwarder and/or forwardee should have to conform to the protocol. Also, > complications regarding Self requirements were brought up. I was the author of the draft proposal discussed in that thread. I’m sitting on a second draft which is about 2/3 complete. I will finish the draft and bring it back up when the core team is ready to consider proposals along these lines again. The ideas I have run in a different and more general direction than what you suggest below. But let’s wait until the time is right to dive into the details. > > For simplicity, if we are going to do this, I propose the following: > > Direct forwarding > • Both the forwarder and the forwardee must conform to the protocol being > forwarded. > • The forwarder’s associated types are inferred to (and must) match the > forwardee’s. > • Requirements the forwarder implements take precedence and are not forwarded. > > Self requirements > • A return type of Self cannot be forwarded. > • A return type of, eg. Self.Element, *can* be forwarded, since the > associated types match. > • A parameter type of Self is forwarded in the natural way, by calling the > forwardee’s implementation with the argument’s forwardee. > > Example of that last point: > > protocol P { func f(_: Self) } > struct Q: P { func f(_: Q){ } } > class C: P { > var q: Q implements P > > // synthesized: > func f(_ a: C) { > q.f(a.q) > } > } > > Some of these restrictions could potentially be lifted in the future, however > for the time being I think they serve an important purpose. > > All that said, I am not yet entirely convinced that protocol forwarding > carries sufficient benefits to justify its addition to the language. > > Nevin > > ___ > 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
Re: [swift-evolution] [pitch] Implementation composition
Protocol forwarding was discussed on-list near the end of 2015 in the thread “[swift-evolution] [Proposal Draft] automatic protocol forwarding”. Feedback was generally positive, though there were disagreements about whether the forwarder and/or forwardee should have to conform to the protocol. Also, complications regarding Self requirements were brought up. For simplicity, if we are going to do this, I propose the following: *Direct forwarding* • Both the forwarder and the forwardee must conform to the protocol being forwarded. • The forwarder’s associated types are inferred to (and must) match the forwardee’s. • Requirements the forwarder implements take precedence and are not forwarded. *Self requirements* • A return type of Self cannot be forwarded. • A return type of, eg. Self.Element, *can* be forwarded, since the associated types match. • A parameter type of Self is forwarded in the natural way, by calling the forwardee’s implementation with the argument’s forwardee. Example of that last point: protocol P { func f(_: Self) } struct Q: P { func f(_: Q){ } } class C: P { var q: Q implements P // synthesized: func f(_ a: C) { q.f(a.q) } } Some of these restrictions could potentially be lifted in the future, however for the time being I think they serve an important purpose. All that said, I am not yet entirely convinced that protocol forwarding carries sufficient benefits to justify its addition to the language. Nevin ___ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution
Re: [swift-evolution] [pitch] Implementation composition
> In what way is this “hiding” protocol conformance? In the examples, MyClass > is declaring conformance to A and B via the Useful protocol composition. > Perhaps I should have made it clearer which bits are new/proposed: Only the > implements word is new here, the protocol composition syntax (A & B) already > exists. > My fault — but imho this "sub-protocol" situation isn't that common, and it would make the proposal simpler if it starts with just forwarding: class MyClass : A { private let a = ImplementsA() implements A ... In this case, there is (small) repetition (which imho isn't that bad — but Kotlin has a nicer syntax for it).___ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution
Re: [swift-evolution] Add code to super methods.
I agree. An NS_REQUIRES_SUPER equivalent was on my list of things to propose during stage 2, and I don't see a reason to enforce order. > On Nov 25, 2016, at 04:42, Tino Heth via swift-evolution >wrote: > > >> What are your thoughts on this? >> >> Just to throw out a strawman: >> >> // Warn if override doesn’t begin with “super.foo()” >> __attribute(swift_requires_super_call_at_begin) >> >> // Warn if override doesn’t end with “super.foo()” >> __attribute(swift_requires_super_call_at_end) > > I myself would already be happy if Swift had an equivalent to > NS_REQUIRES_SUPER (preferably with a different name ;-). > The ability to indicate that super shouldn't be called when overriding would > be nice as well ― both situations happen in Cocoa, and it isn't enforced, but > only documented. > > I don't have any examples where the position of the call to super matters, > and my personal opinion is that this feature wouldn't pay off: > Of course, there are situations where order is important ― but as with > willSet/didSet, it might only be important for the overriding class, not for > super. > > - Tino > ___ > 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
Re: [swift-evolution] [pitch] Implementation composition
Tino, In what way is this “hiding” protocol conformance? In the examples, MyClass is declaring conformance to A and B via the Useful protocol composition. Perhaps I should have made it clearer which bits are new/proposed: Only the implements word is new here, the protocol composition syntax (A & B) already exists. You’re probably right that this is an additive (4.1) thing. But personally I see no harm in building up a backlog of useful proposals to be reviewed next year. The knowledge of what’s to come may also help influence thinking on what’s to come next. Should such discussions be flagged as additive in the subject somehow? I think I asked this before but forgot or missed if there was a response. On Fri, 25 Nov 2016 at 16:21 Tino Heth <2...@gmx.de> wrote: Kotlin has a imho really nice solution for this: Because constructor parameters appear right after the class declaration, you can refer to them in the inheritance-clause. Protocol conformance is a quite important aspect of a type, so I'm not sure if it wise to allow "hiding" it — and I hope the promised macro-system will allow forwarding, so that there is no special syntax needed. Bottom line: Imho it's not the right time for serious discussion (serious means: with the goal of a accepted proposal ;-) ___ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution
Re: [swift-evolution] [pitch] Implementation composition
Kotlin has a imho really nice solution for this: Because constructor parameters appear right after the class declaration, you can refer to them in the inheritance-clause. Protocol conformance is a quite important aspect of a type, so I'm not sure if it wise to allow "hiding" it — and I hope the promised macro-system will allow forwarding, so that there is no special syntax needed. Bottom line: Imho it's not the right time for serious discussion (serious means: with the goal of a accepted proposal ;-) ___ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution
Re: [swift-evolution] [pitch] Implementation composition
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 >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 >
Re: [swift-evolution] Global init() functions
Why not just say that this doesn't affect the removal of types (i.e. they can still be discarded) and add something to prevent specific types being discarded even if they're not statically used? ```swift @nodiscard SomeType ``` This way, rather than a protocol opting in that anything implementing it is automatically `@nodiscard` a program or library would declare some types as non-discardable and could safely say "there will be at least 1 SomeProtocol" available" without saying what specific type it is in the public interface/docs? On Mon, 21 Nov 2016 at 22:50 John McCall via swift-evolution < swift-evolution@swift.org> wrote: > On Nov 20, 2016, at 6:40 AM, Alan Cabrerawrote: > > On Nov 19, 2016, at 8:57 PM, John McCall wrote: > > On Nov 19, 2016, at 6:03 PM, Alan Cabrera wrote: > > On Nov 19, 2016, at 4:02 PM, John McCall wrote: > > On Nov 19, 2016, at 3:31 PM, Alan Cabrera wrote: > > On Nov 19, 2016, at 1:21 PM, John McCall wrote: > > On Nov 19, 2016, at 10:07 AM, Alan Cabrera via swift-evolution < > swift-evolution@swift.org> wrote: > > On Nov 19, 2016, at 9:27 AM, Jean-Daniel wrote: > > > Le 19 nov. 2016 à 15:58, Alan Cabrera via swift-evolution < > swift-evolution@swift.org> a écrit : > > I’m not sure if this was proposed or not; or even if this is a Swift-ly > way of doing things. It would be pretty handy to be able to declare init() > functions in my module to register handlers. It’s a common pattern in > enterprise software. > > Currently, I have to generate a lot of boilerplate code to emulate the > behavior. I think it would be cleaner to have these global init() > functions. > > > I’d rather like a swift attribute equivalent to : __attribute__(( > constructor)) > > It will not force me to call my initializer init, and moreover it will let > me declare multiple functions so I would be able to register multiples > handlers from a single module without having to group all the register call > into a single init() function. > > > I’m not quite following what “__attribute__((constructor))” means; it > looks like an LLVM implementation bit. Do you mean defining a new Swift > declaration attribute named “constructor”? If so, I *really* like that > idea. I think that the specific attribute name “constructor” may be a bit > confusing though, since it’s not really constructing anything specific. > Maybe “startup” would be a more descriptive attribute name? > > @startup > func registerHandlers() { > } > > The attribute would also help the compiler and IDEs prevent direct calling > of the startup functions, thus reinforcing/focusing the startup functions’ > role as global startup functions. Maybe global teardown functions would be > helpful as well. > > I’m going to try goofing around with the idea on my fork. > > > Some sort of reflective discovery would be better, I think. Eager global > initialization is superficially attractive — what could be simpler than > just running some code at program launch? — but as a program scales up and > gains library dependencies, it very quickly runs into problems. What if an > initializer depends on another already having been run? What if an > initializer needs to be sensitive to the arguments or environment? What if > an initializer need to spawn a thread? What if an initializer needs to do > I/O? What if an initializer fails? Global initialization also has a lot > of the same engineering drawbacks as global state, in that once you've > introduced a dependency on it, it's extremely hard to root that out because > entire APIs get built around the assumption that there's no need for an > explicit initialization/configuration/whatever step. And it's also quite > bad for launch performance — perhaps not important for a server, but > important for pretty much every other kind of program — since every > subsystem eagerly initializes itself whether it's going to be used or not, > and that initialization generally has terrible locality. > > > Very good points. I recognize the dangers. However. > > Don’t these problems already exist given that user code can still execute > at program startup? It cannot be denied that the pattern is used and is > extremely useful though, as you point out above, it should be used > carefully. Thinking on it, there are always pros and cons to most language > features and one relies on best practices to avoid shooting oneself in the > foot. For each of the specters listed above, there are simple accepted > practices that can be adopted to avoid them; most of those practices are > already being employed for other situations. > > And the pattern is not just useful in enterprise software. Complex > applications’ app-delegate did-finish-launching methods are chucked full of > hand stitched roll calls to framework initialization code. This needlessly > places a brittle
[swift-evolution] [pitch] Implementation composition
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@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution
Re: [swift-evolution] Add code to super methods.
> What are your thoughts on this? > > Just to throw out a strawman: > > // Warn if override doesn’t begin with “super.foo()” > __attribute(swift_requires_super_call_at_begin) > > // Warn if override doesn’t end with “super.foo()” > __attribute(swift_requires_super_call_at_end) I myself would already be happy if Swift had an equivalent to NS_REQUIRES_SUPER (preferably with a different name ;-). The ability to indicate that super shouldn't be called when overriding would be nice as well — both situations happen in Cocoa, and it isn't enforced, but only documented. I don't have any examples where the position of the call to super matters, and my personal opinion is that this feature wouldn't pay off: Of course, there are situations where order is important — but as with willSet/didSet, it might only be important for the overriding class, not for super. - Tino___ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution