<div dir="ltr">I agree that the solution to any of these problems would be better done with improvements to protocol extensions. Having multiple tools to get the same trick done doesn’t seem worth it in this case.</div><div class="gmail_extra"><br clear="all"><div><div class="gmail_signature">-Tal</div></div>
<br><div class="gmail_quote">On Thu, Apr 21, 2016 at 7:00 AM, James Froggatt via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I sometimes find myself wanting to use private protocols + extensions to try to add public functions to a set of types. Something like this:<br>
<br>
private protocol ArrayBackedType {<br>
var data: [String] {get set}<br>
}<br>
public extension ArrayBackedType: UITableViewDataSource {<br>
/*standard table view methods here*/<br>
}<br>
<br>
This would currently require two changes to the language: public extensions to private protocols, and support for ObjC-compatible functions in extensions (which should be possible for private/internal protocols).<br>
<br>
Additionally, extensions could get the ability to add storage to the (non-imported) type they extend, so:<br>
<br>
internal protocol ArrayBackedType {}<br>
public extension ArrayBackedType: UITableViewDataSource {<br>
private var data: [String] = []<br>
dynamic func tableView(…)<br>
}<br>
<br>
The separate protocol & extension declarations could then get some syntactic sugar:<br>
<br>
/*can't be public, since it can add properties, internal availability matches that of the protocol in the previous example*/<br>
internal protocol extension ArrayBackedType { … }<br>
<br>
or even more concisely:<br>
internal trait ArrayBackedType { … }<br>
<br>
Could traits be constructed from protocol extensions in this way, or otherwise end up competing with them if just some of these features were to be added? My concern is that adding traits as a separate language feature could put them in direct competition with protocol extensions.<br>
<br>
------------ Begin Message ------------<br>
Group: gmane.comp.lang.swift.evolution<br>
MsgID: <<a href="mailto:CAEbsasTVGD6NEZdnFhTMWVwuNc7EBDqatJAJhZFn4vOxdVPBiA@mail.gmail.com">CAEbsasTVGD6NEZdnFhTMWVwuNc7EBDqatJAJhZFn4vOxdVPBiA@mail.gmail.com</a>><br>
<span class=""><br>
Another traits implemenation<br>
<br>
<a href="http://php.net/manual/en/language.oop5.traits.php" rel="noreferrer" target="_blank">http://php.net/manual/en/language.oop5.traits.php</a><br>
On Apr 21, 2016 5:53 PM, "Niall Young via swift-evolution" <<br>
</span><div><div class="h5"><a href="mailto:swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org">swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org</a>> wrote:<br>
<br>
>At Tue Mar 1 19:00:21 CST 2016, Brian Pratt brian at <a href="http://pratt.io" rel="noreferrer" target="_blank">pratt.io</a> wrote:<br>
><br>
>I feel like the solution to the Arrow/Enemy problem that best fits with<br>
>>Swift's current available tools is neither a protocol (which, as you<br>
>>mentioned, doesn't get rid of the initialization/configuration of the<br>
>>member data) or inheritance (which, as you mentioned, can only have one<br>
>>base type) -- it's to extract a third type that handles<br>
>><br>
><br>
>What you're describing sounds _exactly_ like Traits :-)<br>
><br>
><a href="http://scg.unibe.ch/research/traits" rel="noreferrer" target="_blank">http://scg.unibe.ch/research/traits</a><br>
><br>
>Traits could be a peer of extensions, filling a niche that isn't quite the<br>
>same niche as a default implementation, but it could be consistently and<br>
>safely consumed like an extension, with its own rules of consumption<br>
>(flattening) - to implement any need or explicit protocol requirement that<br>
>a Class, Value Type or Protocol has at compile-time.<br>
><br>
>Think of a Trait as providing a consumable set of functions. Now imagine<br>
>that we're combining the collective declarations of 1..N Traits all<br>
>together, consumed by a Class or Value Type (or Protocol!) in a predicable<br>
>and safe way (flattening: see the first Traits white paper).<br>
><br>
>i.e. we get the same result regardless of the order of consumption, how<br>
>many times any given Trait(s) were consumed, Traits dependent on other<br>
>Traits etc. Predictable results, given the same input we always get the<br>
>same output. This is flattening, but read the white papers for more detail.<br>
><br>
>The process of flattening itself could be a peer of the existing rules<br>
>around static dispatch vs. dynamic dispatch around<br>
>default-implementations/extensions vs. class overrides.<br>
><br>
>A Trait declaration could look something ~like:<br>
><br>
>trait TraitX (ProtocolAdherenceY): DependentTrait1,<br>
>DependentTrait2 {<br>
><br>
>private var foo<br>
>private let bah { .. }<br>
><br>
>func fooify { .. }<br>
>mutating func bahify { .. }<br>
>private func hah { .. }<br>
><br>
>}<br>
><br>
>with a Trait being a closure, where _only private_ data Properties can be<br>
>declared, providing 1..N function implementations. It could conform<br>
>_towards_ a Protocol (partial to full conformance), and also be dependent<br>
>upon other names Traits, which would be consumed in parallel as a<br>
>first-class citizen with the Trait that depends on it.<br>
><br>
>Traits could be consumed by a class or value type, to provide function<br>
>implementations which could be satisfying a Protocol implementation<br>
>requirement, along with its own private functions and private data for its<br>
>(private to Trait) local state etc. The consumption syntax I'm still<br>
>unsure of, but a clear declarative "flattens Trait1, Trait2, .. , TraitN"<br>
>or similar would do.<br>
><br>
>The consuming Class or Value Type would remain fully responsible for its<br>
>own Protocol conformance, and if any of the consumed Trait public<br>
>implementations conflict or overlap with each other, then the conflicts<br>
>must be resolved explicitly by the Class or Value Type itself, where it is<br>
>consumed.<br>
><br>
>The resulting "flattened" set of Traits would be input towards the Type's<br>
>own compiler requirements, with the author being required to explicitly<br>
>resolve any and all conflicts at compile-time. Cconsumption at run-time<br>
>could be a later feature as Swift's core stabilises and specific run-time<br>
>metaprogramming facilities are exposed.<br>
><br>
>Explicit conflict resolution, via a flattened 2D matrix of Trait:func<br>
>identifying conflicts that need to be resolved by the consumer, also gives<br>
>reliable results with no cognitive overhead as Brian's identified in<br>
>resolving Mixin consumption. Plus there is no diamond-problem, as there is<br>
>no inheritance. With Traits, it _must_ be resolved explicitly in code,<br>
>with suitable compiler errors for malformed Types that have consumed 1..N<br>
>Trait(s).<br>
><br>
>Stateful Traits suggest that as long as the data is private _to the Trait_<br>
>then we can safely ignore some of the complexity of state in Traits - it<br>
>just isn't exposed as the Trait declaration itself is a closure.<br>
>Dependency on state in the consumer could proxy to<br>
>class/instance/value-type data via Protocol.<br>
><br>
>Swift and Protocols seem like a perfect match for "capital-T" Traits. Any<br>
>thoughts on if this is suitable for a 3.0 or 4.0 Proposal?<br>
><br>
>I've recently built similar mechanisms exploring these concepts with basic<br>
>metaprogramming and a common root class in a dynamic language, but as a<br>
>core language feature of Swift I think it could very much complement the<br>
>existing protocols and extension concepts, with 1..N re-usable<br>
>implementations, and it also could help to resolves the uncertainty/rules<br>
>around static vs. dynamic dispatch: static could remain the domain of<br>
>extensions / default implementations; with dynamic dispatch available to<br>
>Classes and Traits?<br>
><br>
>More Reading:<br>
><br>
><a href="http://scg.unibe.ch/research/traits" rel="noreferrer" target="_blank">http://scg.unibe.ch/research/traits</a><br>
><br>
>Cheers,<br>
><br>
>--<br>
>Niall Young<br>
</div></div>><a href="mailto:niall-AFFH1GffN5hPR4JQBCEnsQ@public.gmane.org">niall-AFFH1GffN5hPR4JQBCEnsQ@public.gmane.org</a><br>
<div><div class="h5">><br>
><br>
>At Tue Mar 1 19:00:21 CST 2016, Brian Pratt brian at <a href="http://pratt.io" rel="noreferrer" target="_blank">pratt.io</a> wrote:<br>
><br>
>I think this sort of composition is preferable to inheritance in a lot of<br>
>>ways, and Swift has some built-in tools that can augment it: a robust<br>
>>protocol and extension system, a type constraint system that allows for<br>
>>lots of flexibility at compile-time, etc.<br>
>><br>
>>Mixins (and in general, the sharing of code primarily via inheritance)<br>
>>tend<br>
>>to create large objects with lots of responsibilities, and that tends to<br>
>>bloat APIs as you need to either pick extremely specific names to avoid<br>
>>collisions, or worse, keep the cognitive overhead of "shoot, what is this<br>
>>method aliased to again?" in your head all the time. If something *is*<br>
>>both<br>
>>an A and a B, it needs to act like (and speak the same language of) an A<br>
>>or<br>
>>a B *all* of the time.<br>
>><br>
>>Beyond this, I think it's going to be extremely complex managing<br>
>>compile-time type constraints with renames in place. Let's say I have a<br>
>>class C that inherits from bases A and B, which implement protocol P and Q<br>
>>respectively, and there's a naming collision. Functions that expect Ps or<br>
>>Qs will have to know about the renaming of conflicts from the combination<br>
>>of A+B? Unless I'm missing something, it feels like this complexity would<br>
>>continue to spread out to all sorts of collaborators, when the current<br>
>>system isolates it much more effectively.<br>
>><br>
><br>
>I think protocols and protocol extensions (mixed with lots of composition)<br>
>>is a better scenario than abstract classes or multiple inheritance, and<br>
>>therefore, I'm still a -1 on mixins in Swift (strictly on principle; this<br>
>>proposal actually argues the case very well).<br>
>><br>
>>- Brian<br>
>><br>
><br>
>And agreed Thorsten!:<br>
><br>
>Unfortunately the current discussions about Mixins, abstract classes, POP<br>
>>>vs. OOP suffer from having forgotten achievements of the past which<br>
>>>results<br>
>>>in creating differences where none should be.<br>
>>><br>
>><br>
>It is unfortunate and IMO just for historical reasons that there is a<br>
>>>dichotomy between protocols and classes at all instead of having just<br>
>>>classes with multiple inheritance done right (and abstract methods).<br>
>>><br>
>><br>
>- We should extend protocols to support real multiple inheritance with<br>
>>>renaming<br>
>>><br>
>><br>
>-Thorsten<br>
>>><br>
>>_______________________________________________<br>
>swift-evolution mailing list<br>
</div></div>><a href="mailto:swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org">swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org</a><br>
><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
><br>
<br>
<br>
<br>
------------- End Message -------------<br>
<br>
<br>
<br>
>From James F<br>
<div class="HOEnZb"><div class="h5">_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</div></div></blockquote></div><br></div>