[swift-evolution] [Draft] Mixins

Tim Hawkins tim.thawkins at gmail.com
Thu Apr 21 04:57:37 CDT 2016


Another traits implemenation

http://php.net/manual/en/language.oop5.traits.php
On Apr 21, 2016 5:53 PM, "Niall Young via swift-evolution" <
swift-evolution at swift.org> wrote:

> At Tue Mar 1 19:00:21 CST 2016, Brian Pratt brian at pratt.io wrote:
>
> I feel like the solution to the Arrow/Enemy problem that best fits with
>> Swift's current available tools is neither a protocol (which, as you
>> mentioned, doesn't get rid of the initialization/configuration of the
>> member data) or inheritance (which, as you mentioned, can only have one
>> base type) -- it's to extract a third type that handles
>>
>
> What you're describing sounds _exactly_ like Traits :-)
>
>         http://scg.unibe.ch/research/traits
>
> Traits could be a peer of extensions, filling a niche that isn't quite the
> same niche as a default implementation, but it could be consistently and
> safely consumed like an extension, with its own rules of consumption
> (flattening) - to implement any need or explicit protocol requirement that
> a Class, Value Type or Protocol has at compile-time.
>
> Think of a Trait as providing a consumable set of functions.  Now imagine
> that we're combining the collective declarations of 1..N Traits all
> together, consumed by a Class or Value Type (or Protocol!) in a predicable
> and safe way (flattening: see the first Traits white paper).
>
> i.e. we get the same result regardless of the order of consumption, how
> many times any given Trait(s) were consumed, Traits dependent on other
> Traits etc.  Predictable results, given the same input we always get the
> same output.  This is flattening, but read the white papers for more detail.
>
> The process of flattening itself could be a peer of the existing rules
> around static dispatch vs. dynamic dispatch around
> default-implementations/extensions vs. class overrides.
>
> A Trait declaration could look something ~like:
>
>         trait TraitX (ProtocolAdherenceY): DependentTrait1,
> DependentTrait2 {
>
>                 private var foo
>                 private let bah { .. }
>
>                 func fooify { .. }
>                 mutating func bahify { .. }
>                 private func hah { .. }
>
>         }
>
> with a Trait being a closure, where _only private_ data Properties can be
> declared, providing 1..N function implementations.  It could conform
> _towards_ a Protocol (partial to full conformance), and also be dependent
> upon other names Traits, which would be consumed in parallel as a
> first-class citizen with the Trait that depends on it.
>
> Traits could be consumed by a class or value type, to provide function
> implementations which could be satisfying a Protocol implementation
> requirement, along with its own private functions and private data for its
> (private to Trait) local state etc.  The consumption syntax I'm still
> unsure of, but a clear declarative "flattens Trait1, Trait2, .. , TraitN"
> or similar would do.
>
> The consuming Class or Value Type would remain fully responsible for its
> own Protocol conformance, and if any of the consumed Trait public
> implementations conflict or overlap with each other, then the conflicts
> must be resolved explicitly by the Class or Value Type itself, where it is
> consumed.
>
> The resulting "flattened" set of Traits would be input towards the Type's
> own compiler requirements, with the author being required to explicitly
> resolve any and all conflicts at compile-time.  Cconsumption at run-time
> could be a later feature as Swift's core stabilises and specific run-time
> metaprogramming facilities are exposed.
>
> Explicit conflict resolution, via a flattened 2D matrix of Trait:func
> identifying conflicts that need to be resolved by the consumer, also gives
> reliable results with no cognitive overhead as Brian's identified in
> resolving Mixin consumption.  Plus there is no diamond-problem, as there is
> no inheritance.  With Traits, it _must_ be resolved explicitly in code,
> with suitable compiler errors for malformed Types that have consumed 1..N
> Trait(s).
>
> Stateful Traits suggest that as long as the data is private _to the Trait_
> then we can safely ignore some of the complexity of state in Traits - it
> just isn't exposed as the Trait declaration itself is a closure.
> Dependency on state in the consumer could proxy to
> class/instance/value-type data via Protocol.
>
> Swift and Protocols seem like a perfect match for "capital-T" Traits.  Any
> thoughts on if this is suitable for a 3.0 or 4.0 Proposal?
>
> I've recently built similar mechanisms exploring these concepts with basic
> metaprogramming and a common root class in a dynamic language, but as a
> core language feature of Swift I think it could very much complement the
> existing protocols and extension concepts, with 1..N re-usable
> implementations, and it also could help to resolves the uncertainty/rules
> around static vs. dynamic dispatch: static could remain the domain of
> extensions / default implementations; with dynamic dispatch available to
> Classes and Traits?
>
> More Reading:
>
>         http://scg.unibe.ch/research/traits
>
> Cheers,
>
> --
> Niall Young
> niall at iinet.net.au
>
>
> At Tue Mar 1 19:00:21 CST 2016, Brian Pratt brian at pratt.io wrote:
>
> I think this sort of composition is preferable to inheritance in a lot of
>> ways, and Swift has some built-in tools that can augment it: a robust
>> protocol and extension system, a type constraint system that allows for
>> lots of flexibility at compile-time, etc.
>>
>> Mixins (and in general, the sharing of code primarily via inheritance)
>> tend
>> to create large objects with lots of responsibilities, and that tends to
>> bloat APIs as you need to either pick extremely specific names to avoid
>> collisions, or worse, keep the cognitive overhead of "shoot, what is this
>> method aliased to again?" in your head all the time. If something *is*
>> both
>> an A and a B, it needs to act like (and speak the same language of) an A
>> or
>> a B *all* of the time.
>>
>> Beyond this, I think it's going to be extremely complex managing
>> compile-time type constraints with renames in place. Let's say I have a
>> class C that inherits from bases A and B, which implement protocol P and Q
>> respectively, and there's a naming collision. Functions that expect Ps or
>> Qs will have to know about the renaming of conflicts from the combination
>> of A+B? Unless I'm missing something, it feels like this complexity would
>> continue to spread out to all sorts of collaborators, when the current
>> system isolates it much more effectively.
>>
>
> I think protocols and protocol extensions (mixed with lots of composition)
>> is a better scenario than abstract classes or multiple inheritance, and
>> therefore, I'm still a -1 on mixins in Swift (strictly on principle; this
>> proposal actually argues the case very well).
>>
>> - Brian
>>
>
> And agreed Thorsten!:
>
> Unfortunately the current discussions about Mixins, abstract classes, POP
>>> vs. OOP suffer from having forgotten achievements of the past which
>>> results
>>> in creating differences where none should be.
>>>
>>
> It is unfortunate and IMO just for historical reasons that there is a
>>> dichotomy between protocols and classes at all instead of having just
>>> classes with multiple inheritance done right (and abstract methods).
>>>
>>
> - We should extend protocols to support real multiple inheritance with
>>> renaming
>>>
>>
> -Thorsten
>>>
>> _______________________________________________
> 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/20160421/217ba4af/attachment.html>


More information about the swift-evolution mailing list