[Draft] Mixins


(Anton Zhilin) #1

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!


(Howard Lovatt) #2

I like the proposal but would suggest you rename it Trait and not Mixin,
since you proposal has Trait and not Mixin behaviour. The difference is
that the order of inheritance is not important with Traits but is with
Mixins, EG:

    protocol A { let msg = "A" }
    protocol B { let msg = "B" }
    struct MixinAB: A, B {}
    MixinAB().msg // B

  Whereas

    struct MixinBA: B, A {}
    MixinBA().msg // A

With traits the order is not important, and has to be resolved by the
programmer when a conflict arises:

    struct ErrorAB: A, B {} // An error because there are two `msg`s.

You have to do:

    struct TraitAB: A, B { // Could be B, A - makes no difference
        let msg = A.msg // Select A's definition, could be `= B.msg`, could
be `= 3` (i.e. any valid Swift)
    }

As an aside I don't get what you mean by your example:

protocol<A, B> // error

Protocols cannot be generic!

···

On Sunday, 28 February 2016, Anton Zhilin via swift-evolution < swift-evolution@swift.org> wrote:

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!
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <javascript:;>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-- Howard.


(Joe Groff) #3

Howard Lovatt via swift-evolution

I like the proposal but would suggest you rename it Trait and not Mixin,
since you proposal has Trait and not Mixin behaviour. The difference is
that the order of inheritance is not important with Traits but is with
Mixins, EG:

    protocol A { let msg = "A" }
    protocol B { let msg = "B" }
    struct MixinAB: A, B {}
    MixinAB().msg // B

  Whereas

    struct MixinBA: B, A {}
    MixinBA().msg // A

With traits the order is not important, and has to be resolved by the
programmer when a conflict arises:

    struct ErrorAB: A, B {} // An error because there are two `msg`s.

You have to do:

    struct TraitAB: A, B { // Could be B, A - makes no difference
        let msg = A.msg // Select A's definition, could be `= B.msg`, could
be `= 3` (i.e. any valid Swift)
    }

As an aside I don't get what you mean by your example:

protocol<A, B> // error

This is the spelling for the protocol composition of A and B.

···

<swift-evolution@swift.org> wrote:

Protocols cannot be generic!

On Sunday, 28 February 2016, Anton Zhilin via swift-evolution < > swift-evolution@swift.org> wrote:

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!
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <javascript:;>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Anton Zhilin) #4

I understand now where some misunderstandment comes from. I haven't really
used any languages with traits, but looking at the definition, my proposal
surely talks about "traits with state".
I currently don't suggest any ways to resolve these conflicts. Adding it to
future directions for now.
protocol<A, B> in Swift is the same as protocol InlineProtocol : A, B { }

···

2016-02-28 4:17 GMT+03:00 Howard Lovatt <howard.lovatt@gmail.com>:

I like the proposal but would suggest you rename it Trait and not Mixin,
since you proposal has Trait and not Mixin behaviour. The difference is
that the order of inheritance is not important with Traits but is with
Mixins, EG:

    protocol A { let msg = "A" }
    protocol B { let msg = "B" }
    struct MixinAB: A, B {}
    MixinAB().msg // B

  Whereas

    struct MixinBA: B, A {}
    MixinBA().msg // A

With traits the order is not important, and has to be resolved by the
programmer when a conflict arises:

    struct ErrorAB: A, B {} // An error because there are two `msg`s.

You have to do:

    struct TraitAB: A, B { // Could be B, A - makes no difference
        let msg = A.msg // Select A's definition, could be `= B.msg`,
could be `= 3` (i.e. any valid Swift)
    }

As an aside I don't get what you mean by your example:

protocol<A, B> // error

Protocols cannot be generic!

On Sunday, 28 February 2016, Anton Zhilin via swift-evolution < > swift-evolution@swift.org> wrote:

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!
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-- Howard.


(Howard Lovatt) #5

Thanks for clarifying `protocol<A, B>`. In that case `protocol<A, B>` is
not necessarily an error for traits, but the ambiguity needs resolving.

···

On Sunday, 28 February 2016, Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

Howard Lovatt via swift-evolution
<swift-evolution@swift.org <javascript:;>> wrote:
> I like the proposal but would suggest you rename it Trait and not Mixin,
> since you proposal has Trait and not Mixin behaviour. The difference is
> that the order of inheritance is not important with Traits but is with
> Mixins, EG:
>
> protocol A { let msg = "A" }
> protocol B { let msg = "B" }
> struct MixinAB: A, B {}
> MixinAB().msg // B
>
> Whereas
>
> struct MixinBA: B, A {}
> MixinBA().msg // A
>
> With traits the order is not important, and has to be resolved by the
> programmer when a conflict arises:
>
> struct ErrorAB: A, B {} // An error because there are two `msg`s.
>
> You have to do:
>
> struct TraitAB: A, B { // Could be B, A - makes no difference
> let msg = A.msg // Select A's definition, could be `= B.msg`,
could
> be `= 3` (i.e. any valid Swift)
> }
>
> As an aside I don't get what you mean by your example:
>
> protocol<A, B> // error

This is the spelling for the protocol composition of A and B.

>
> Protocols cannot be generic!
>
> On Sunday, 28 February 2016, Anton Zhilin via swift-evolution < > > swift-evolution@swift.org <javascript:;>> wrote:
>
>> 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!
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <javascript:;> <javascript:;>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <javascript:;>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-- Howard.