[swift-evolution] [Draft] Mixins

Anton Zhilin antonyzhilin at gmail.com
Sat Feb 27 15:57:12 CST 2016


0. Please read the whole proposal and this whole message before replying.

1.
> In short words, protocol will became a sort of class and no longer a true kind of contract to conform to.

There is an option to introduce "mixin" keyword:
mixin M {
    var storage: Int = 0
}
It won't cause confusion with today's protocols.
For difference from classes, see under 3.

2.
> What about compatibility with Objective C ?

Protocols cannot inherit from classes, including NSObject.
[Warning: IMO ahead]
But I personally think that we should move from abstract classes in Obj-C, where possible. Actually, all classes in Obj-C can be instantiated, so I consider this a bad abstraction.

3.
> (see David's message)
Firstly, what you've shown is not a diamond problem. No dequate programming language would allow you to do what you've shown. Secondly, please read the whole proposal, as I specifically addressed the issue there.

Now, to difference from classes.
The largest difference between classes and mixins comes in inheritance. We can allow multiple inheritance, because we can solve diamond problem with mixins.
Let's take the example from my proposal:

protocol A { var x: Int = 1 }
protocol B: A { }
protocol C: A { }
struct D : B, C { }

What really happens here is the following:

protocol ASelf { var x: Int = 1 }
protocol BSelf { }
protocol CSelf { }
struct D : ASelf, BSelf, CSelf { }

We can do this, because mixins are statically dispatched. The compiler will enumerate all included mixins and mix in only one version of each.
I said statically dispatched, but in Swift, compiler can automatically create wrappers with necessary closures inside if we need dynamic dispatch for protocols, so that is not a real concern.
Diamond problem is solved the same way in Python and Ruby, so I'm not inventing something new here.
Mixins tend to "mix in behaviours". Let's take an example usage of diamond pattern:

protocol SignalSender {
    private var slots: [String: [() -> ()]] = []
    func connect(signal: String, to slot: () -> ()) { ... }
    func fire(signal: String) { ... }
}
protocol A : SignalSender {
    // Use signal functionality
}
protocol B : SignalSender {
    // Use signal functionality
}
struct C : A, B { }

A and B both use a single SignalSender, incorporated within final object. If SignalSender supports its invariants through incapsulation, nothing will ever break them. If it doesn't, then, well, this mixin is not perfectly suited for multiple inheritance.

If you have reached this far, thank you!


More information about the swift-evolution mailing list