[swift-evolution] [Draft] Mixins

David Waite david at alkaline-solutions.com
Thu Apr 21 09:53:40 CDT 2016


> On Apr 21, 2016, at 3:52 AM, 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).

extensions give us something trait-like, but with only one, non-opt-in implementation and usually per protocol. I’d imagine a true trait system to allow for more specific default implementations of Sequence, for example.

> 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 typically cannot declare fields/state. Is this not where you start to cross over to Mixins?

I attempted to model this (today) via delegates for behavioral dependencies on traits and self-wiring, but this creates issues with value type copying and circular references in reference types. For that reason, I didn’t feel it was appropriate to make a formal trait proposal until more definition toward behaviors (e.g. Joe Groff’s property behaviors) or macros were in the discussion.

<snip>
> 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.

Yes, but this means that said data may be duplicated and need to be kept in sync between traits and the main type. It also means that traits cannot be used while extending an existing type to meet new protocol requirements outside a module, as that may change the size of the type itself to be different than what precompiled code expects.

-DW



More information about the swift-evolution mailing list