[Draft] Mixins

"Mixins" is as an extension for POP that adds the ability to mix in stored
properties. Deciding by possibilities/power:
protocol < class
[protocol, mixin] ~= class
~= means approximately equals

Classes are still more powerful in that they can be reference counted and
can form hierarchies of fully defined types. For all other purposes:
[protocol, mixin] = class

So we still have OOP and POP (class and struct), but POP gets enhanced.

···

>* On Feb 28, 2016, at 09:02, Trent Nadeau via swift-evolution <swift-evolution at swift.org <http://swift.org>> wrote:
*> >* In the proposal, I would recommend stressing how this both subsumes abstract classes and allows similar functionality on value types.
*>
On the subject of ‘subsuming’… it seems with this proposal we now have three approaches to solving the problem of code reuse/specialization: OOP, POP, and Mixin Oriented Programming (MOP). The decision about which approach to use makes the learning curve steeper. Perhaps there is some way to generalize or unify the three approaches, and flatten the learning curve?

In any case, I’m hesitant to add new directions to the language until the current ones have been given the benefit of some more time.

Matt

I have rewritten almost the whole proposal in the last 10 hours. I
encourage everyone interested to reread it and suggest fixes, improvements,
as well as new directions for discussion.

It would be helpful if you include the new draft. Or at least a link to it.

···

On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

I have rewritten almost the whole proposal in the last 10 hours. I encourage everyone interested to reread it and suggest fixes, improvements, as well as new directions for discussion.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Link to the proposal: mixins-draft.md · GitHub

···

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com>:

It would be helpful if you include the new draft. Or at least a link to it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I
encourage everyone interested to reread it and suggest fixes, improvements,
as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

The quoted portion of the proposal below doesn't make any sense to me.
Subclasses can't be value types. Do you mean the structs could have similar
functionality?

Firstly, only classes can inherit from such abstract classes, while it can
be easily seen that some subclasses ofCachingSerializable or SignalSender would
naturally have value semantics (be structs, in other words).

···

On Sun, Feb 28, 2016 at 5:03 PM, Антон Жилин <swift-evolution@swift.org> wrote:

Link to the proposal: mixins-draft.md · GitHub

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com>:

It would be helpful if you include the new draft. Or at least a link to
it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution < >> swift-evolution@swift.org> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I
encourage everyone interested to reread it and suggest fixes, improvements,
as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Trent Nadeau

I understood him to mean that abstract classes cannot be used for value types, but it would be natural to want that functionality. Mixins would provide that capability for value types as well as classes.

···

On Feb 28, 2016, at 7:41 PM, Trent Nadeau <tanadeau@gmail.com> wrote:

The quoted portion of the proposal below doesn't make any sense to me. Subclasses can't be value types. Do you mean the structs could have similar functionality?

Firstly, only classes can inherit from such abstract classes, while it can be easily seen that some subclasses ofCachingSerializable or SignalSender would naturally have value semantics (be structs, in other words).

On Sun, Feb 28, 2016 at 5:03 PM, Антон Жилин <swift-evolution@swift.org> wrote:
Link to the proposal: mixins-draft.md · GitHub

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com>:

It would be helpful if you include the new draft. Or at least a link to it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I encourage everyone interested to reread it and suggest fixes, improvements, as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Trent Nadeau

Sorry, I understood "that phrase" to mean what I just stated.

···

On Feb 28, 2016, at 8:03 PM, Step C <schristopher@bignerdranch.com> wrote:

I understood him to mean that abstract classes cannot be used for value types, but it would be natural to want that functionality. Mixins would provide that capability for value types as well as classes.

On Feb 28, 2016, at 7:41 PM, Trent Nadeau <tanadeau@gmail.com> wrote:

The quoted portion of the proposal below doesn't make any sense to me. Subclasses can't be value types. Do you mean the structs could have similar functionality?

Firstly, only classes can inherit from such abstract classes, while it can be easily seen that some subclasses ofCachingSerializable or SignalSender would naturally have value semantics (be structs, in other words).

On Sun, Feb 28, 2016 at 5:03 PM, Антон Жилин <swift-evolution@swift.org> wrote:
Link to the proposal: mixins-draft.md · GitHub

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com>:

It would be helpful if you include the new draft. Or at least a link to it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I encourage everyone interested to reread it and suggest fixes, improvements, as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Trent Nadeau

I'm prepairing to create a pull request, so I moved the proposal from Gist
to my fork of swift-evolution.
Link to the proposal new and hopefully final home:

Should I create a pull request right now or wait a bit?

Some details need to be discussed:

1. Do mixins need associated types? Would generics be more appropriate to
them?

2. `mixin` vs `mixin protocol`. On one hand, `mixin protocol` does not
require a keyword.
On the other hand, as stated in a special section, mixins cannot be used
everywhere a protocol can. Protocols, mixins, traits, interfaces are all
different entities.

3. `mixin` vs `trait`. Please read Wiki or any other source and tell what
is a better name.

4. Objective-C interfacing. Do we have to require it now? (I doubt so.) Can
we allow mixing-in Swift mixins to Objective-C classes?

5. Are you happy with Initializers section?

6. Can motivation examples be improved?

···

2016-02-29 4:07 GMT+03:00 Step C <schristopher@bignerdranch.com>:

Sorry, I understood "that phrase" to mean what I just stated.

On Feb 28, 2016, at 8:03 PM, Step C <schristopher@bignerdranch.com> wrote:

I understood him to mean that abstract classes cannot be used for value
types, but it would be natural to want that functionality. Mixins would
provide that capability for value types as well as classes.

On Feb 28, 2016, at 7:41 PM, Trent Nadeau <tanadeau@gmail.com> wrote:

The quoted portion of the proposal below doesn't make any sense to me.
Subclasses can't be value types. Do you mean the structs could have similar
functionality?

Firstly, only classes can inherit from such abstract classes, while it can
be easily seen that some subclasses ofCachingSerializable or SignalSender would
naturally have value semantics (be structs, in other words).

On Sun, Feb 28, 2016 at 5:03 PM, Антон Жилин <swift-evolution@swift.org> > wrote:

Link to the proposal: mixins-draft.md · GitHub

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com>:

It would be helpful if you include the new draft. Or at least a link to
it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution < >>> swift-evolution@swift.org> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I
encourage everyone interested to reread it and suggest fixes, improvements,
as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Trent Nadeau

First, thank you very much for starting this discussion!

I have been thinking of an alternate strategy using traits, partially based on http://web.cecs.pdx.edu/~black/publications/TR_CSE_02-012.pdf .

In my alternate strategy, you would have trait objects which behave similar to value types. They would expose methods/properties, can conform to protocols, and can also require other properties/methods via delegate protocols. When composed by an outer object, the properties/methods and protocol conformance can be either directly addressed or mapped (via some language syntax or via explicit wrapping functions) to the outer object’s usage contract as new properties/methods/protocol conformance.

The trait objects do not hold state, although the delegate protocols they require for usage can provide said state.

Similar to property behaviors, one could make a naive implementation today via generic wrappers. However, this would require duplicated state to provide the delegate protocols where needed, as well as complexity of use and memory duplication when those implementations are backed by value types. Thus, this feature falls into a similar camp of needing compiler support for optimal memory use/performance. While traits behave as if they are separate objects, they should not be treated as such and fall closer into the realm of macros.

You would not include these traits via the inheritance/implementation mechanism - they would not participate in an object’s superclass hierarchy or protocol conformance. Instead they act closer to ‘let’ properties.

Language syntax would be used to selectively map methods, properties, and full protocol conformance from a trait to the externally accessible interface of a composing object. Likewise, you can map properties/methods/protocol conformance of your object to fulfill the delegate protocol requirements of a trait. Unmapped features of a trait are not visible outside an object.

Conflicts between multiple traits just prevent the mapping syntax. However, you should be able to resolve this by writing your own implementations for the conflicting traits on the composing object.

Finally, as indicated before a trait can require multiple delegate protocols, such as how UITableView has both UI behavior and data delegate interfaces. “Mixin” behavior could come from having an object which has a default implementation of that data protocol, and mapping to a property holding an instance of that object within the composing type.

-DW

···

On Feb 29, 2016, at 11:51 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

I'm prepairing to create a pull request, so I moved the proposal from Gist to my fork of swift-evolution.
Link to the proposal new and hopefully final home:
https://github.com/Anton3/swift-evolution/blob/mixins/proposals/NNNN-mixins.md

Should I create a pull request right now or wait a bit?

Some details need to be discussed:

1. Do mixins need associated types? Would generics be more appropriate to them?

2. `mixin` vs `mixin protocol`. On one hand, `mixin protocol` does not require a keyword.
On the other hand, as stated in a special section, mixins cannot be used everywhere a protocol can. Protocols, mixins, traits, interfaces are all different entities.

3. `mixin` vs `trait`. Please read Wiki or any other source and tell what is a better name.

4. Objective-C interfacing. Do we have to require it now? (I doubt so.) Can we allow mixing-in Swift mixins to Objective-C classes?

5. Are you happy with Initializers section?

6. Can motivation examples be improved?

2016-02-29 4:07 GMT+03:00 Step C <schristopher@bignerdranch.com <mailto:schristopher@bignerdranch.com>>:
Sorry, I understood "that phrase" to mean what I just stated.

On Feb 28, 2016, at 8:03 PM, Step C <schristopher@bignerdranch.com <mailto:schristopher@bignerdranch.com>> wrote:

I understood him to mean that abstract classes cannot be used for value types, but it would be natural to want that functionality. Mixins would provide that capability for value types as well as classes.

On Feb 28, 2016, at 7:41 PM, Trent Nadeau <tanadeau@gmail.com <mailto:tanadeau@gmail.com>> wrote:

The quoted portion of the proposal below doesn't make any sense to me. Subclasses can't be value types. Do you mean the structs could have similar functionality?

Firstly, only classes can inherit from such abstract classes, while it can be easily seen that some subclasses ofCachingSerializable or SignalSender would naturally have value semantics (be structs, in other words).

On Sun, Feb 28, 2016 at 5:03 PM, Антон Жилин <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Link to the proposal: mixins-draft.md · GitHub

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com <mailto:schristopher@bignerdranch.com>>:
It would be helpful if you include the new draft. Or at least a link to it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I encourage everyone interested to reread it and suggest fixes, improvements, as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

--
Trent Nadeau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I'm prepairing to create a pull request, so I moved the proposal from Gist to my fork of swift-evolution.
Link to the proposal new and hopefully final home:
https://github.com/Anton3/swift-evolution/blob/mixins/proposals/NNNN-mixins.md

Should I create a pull request right now or wait a bit?

Some details need to be discussed:

1. Do mixins need associated types? Would generics be more appropriate to them?

2. `mixin` vs `mixin protocol`. On one hand, `mixin protocol` does not require a keyword.
On the other hand, as stated in a special section, mixins cannot be used everywhere a protocol can. Protocols, mixins, traits, interfaces are all different entities.

Protocols and mixins address different problems. A protocol defines a statement of conformance. A mixin defines code and/or state to share. Why not allow mixins to conform to protocols?

3. `mixin` vs `trait`. Please read Wiki or any other source and tell what is a better name.

Traits typically do not define state. If you want to define state, then you're working with mixins.

4. Objective-C interfacing. Do we have to require it now? (I doubt so.) Can we allow mixing-in Swift mixins to Objective-C classes?

Why? This is Swift.

5. Are you happy with Initializers section?

IMHO, initializers should only be defined by entities.

6. Can motivation examples be improved?

Yes.

7. Need to address name collisions? I love Ruby, but there are many poorly written mixins out there and they quickly become the bane of a developer's existence. What if the name of a mixin qualified the names of the methods and state contained by the mixin?

···

On Feb 29, 2016, at 1:51 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

2016-02-29 4:07 GMT+03:00 Step C <schristopher@bignerdranch.com <mailto:schristopher@bignerdranch.com>>:
Sorry, I understood "that phrase" to mean what I just stated.

On Feb 28, 2016, at 8:03 PM, Step C <schristopher@bignerdranch.com <mailto:schristopher@bignerdranch.com>> wrote:

I understood him to mean that abstract classes cannot be used for value types, but it would be natural to want that functionality. Mixins would provide that capability for value types as well as classes.

On Feb 28, 2016, at 7:41 PM, Trent Nadeau <tanadeau@gmail.com <mailto:tanadeau@gmail.com>> wrote:

The quoted portion of the proposal below doesn't make any sense to me. Subclasses can't be value types. Do you mean the structs could have similar functionality?

Firstly, only classes can inherit from such abstract classes, while it can be easily seen that some subclasses ofCachingSerializable or SignalSender would naturally have value semantics (be structs, in other words).

On Sun, Feb 28, 2016 at 5:03 PM, Антон Жилин <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Link to the proposal: mixins-draft.md · GitHub

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com <mailto:schristopher@bignerdranch.com>>:
It would be helpful if you include the new draft. Or at least a link to it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I encourage everyone interested to reread it and suggest fixes, improvements, as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

--
Trent Nadeau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Before further work on the details of the design, I urge you to focus on the problem to be solved by the proposed changes. I felt strongly that the abstract classes proposal also foundered on this crucial point (https://jeremywsherman.com/blog/2016/02/29/review-se-0026-abstract-classes-and-methods/\).

Currently the primary motivation is "fixing drawbacks of abstract classes". But Swift does not have abstract classes (yet - review is pending), so it does not have any of their drawbacks. This leaves a motivation vacuum.

Mixins have a long (and confused - the early Lisp implementations appear to have been misunderstood, see http://www.dreamsongs.com/Files/Incommensurability.pdf\) history. There are plenty of languages now that include them or variations on them. The current proposal does not take advantage of this rich living resource to feature problems solved (and new problems created) by mixins, nor does it situate the design relative to prior art / related literature (choose the more significant term depending on your exposure to either IP law or conference proceedings ;).

When it comes of Lisp mixins (flavors), their runtime behavior was more like the advice features of aspect-oriented programming systems, with code executing before, after, or around a primary method. (The actual way mixin functionality was composed with a primary method was programmer controllable, and CLOS provided several standard combinations out of the box.)

The high-level gist is that mixins sought to provide declarative composition of behavior - "it's this, with a hint of this, and some of that tossed in to spice up the basic behavior" - vs the procedural composition afforded by inheritance - "and now super.doSomething, just like any other procedure call". willSet/didSet bear some resemblance to before/after mixins, but are currently rather limited in applicability.

What could we accomplish with before advice on viewDidLoad? Would this solve any thorny problems we have now? Might adding aspect oriented programming features to protocols avoid the sticky issue of stored properties while neatly solving real problems?

I don't know the answers, but feel a convincing proposal will speak to how it will solve problems, while a truly wondrous proposal will relieve me of burthens I didn't even know I had been shouldering all this time.

···

--
Jeremy W. Sherman
http://jeremywsherman.com/

El 29-02-2016, a las 13:51, Антон Жилин via swift-evolution <swift-evolution@swift.org> escribió:

I'm prepairing to create a pull request, so I moved the proposal from Gist to my fork of swift-evolution.
Link to the proposal new and hopefully final home:
https://github.com/Anton3/swift-evolution/blob/mixins/proposals/NNNN-mixins.md

Should I create a pull request right now or wait a bit?

Some details need to be discussed:

1. Do mixins need associated types? Would generics be more appropriate to them?

2. `mixin` vs `mixin protocol`. On one hand, `mixin protocol` does not require a keyword.
On the other hand, as stated in a special section, mixins cannot be used everywhere a protocol can. Protocols, mixins, traits, interfaces are all different entities.

3. `mixin` vs `trait`. Please read Wiki or any other source and tell what is a better name.

4. Objective-C interfacing. Do we have to require it now? (I doubt so.) Can we allow mixing-in Swift mixins to Objective-C classes?

5. Are you happy with Initializers section?

6. Can motivation examples be improved?

2016-02-29 4:07 GMT+03:00 Step C <schristopher@bignerdranch.com>:

Sorry, I understood "that phrase" to mean what I just stated.

On Feb 28, 2016, at 8:03 PM, Step C <schristopher@bignerdranch.com> wrote:

I understood him to mean that abstract classes cannot be used for value types, but it would be natural to want that functionality. Mixins would provide that capability for value types as well as classes.

On Feb 28, 2016, at 7:41 PM, Trent Nadeau <tanadeau@gmail.com> wrote:

The quoted portion of the proposal below doesn't make any sense to me. Subclasses can't be value types. Do you mean the structs could have similar functionality?

Firstly, only classes can inherit from such abstract classes, while it can be easily seen that some subclasses ofCachingSerializable or SignalSender would naturally have value semantics (be structs, in other words).

On Sun, Feb 28, 2016 at 5:03 PM, Антон Жилин <swift-evolution@swift.org> wrote:
Link to the proposal: mixins-draft.md · GitHub

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com>:

It would be helpful if you include the new draft. Or at least a link to it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I encourage everyone interested to reread it and suggest fixes, improvements, as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Trent Nadeau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

In line below.

  -- Howard.

I'm prepairing to create a pull request, so I moved the proposal from Gist
to my fork of swift-evolution.
Link to the proposal new and hopefully final home:

https://github.com/Anton3/swift-evolution/blob/mixins/proposals/NNNN-mixins.md

Should I create a pull request right now or wait a bit?

Some details need to be discussed:

1. Do mixins need associated types? Would generics be more appropriate to
them?

I would prefer generics so that they work seamlessly with structs and
classes that use generics without having to use type constraints via where
clauses

2. `mixin` vs `mixin protocol`. On one hand, `mixin protocol` does not
require a keyword.
On the other hand, as stated in a special section, mixins cannot be used
everywhere a protocol can. Protocols, mixins, traits, interfaces are all
different entities.

trait, not trait protocol - see below

3. `mixin` vs `trait`. Please read Wiki or any other source and tell what
is a better name.

trait since the proposal is very close to "Traits: Composable Units of
Behaviour", by Nathanael Scha ̈rli, Ste ́phane Ducasse, Oscar Nierstrasz,
and Andrew P. Black, which is the paper that 1st proposed traits.

4. Objective-C interfacing. Do we have to require it now? (I doubt so.)
Can we allow mixing-in Swift mixins to Objective-C classes?

No protocols are good for that. Keep it simple at 1st, can always be added
latter.

5. Are you happy with Initializers section?

Yes

6. Can motivation examples be improved?

How about adding implementing CustomStringConvertable and Equatable, e.g.:

mixing Shape: CustomStringConvertable, Equatable {

var center: CGPoint = CGPoint.zero

var bounds: CGSize { get } // Note: not implemented

var description: String { return "Shape(center: x: \(center), bounds:
\(bounds))"

}

func ==(lhs: Shape, rhs: Shape) -> Bool {

return lhs.center == rhs.center && lhs.bounds == rhs.bounds

}

mixing Line: CustomStringConvertable, Equatable {

var color = UIColor.blackColor()

var width = 1
var description: String { return "Line(color: x: \(color), width: \(width))"

}

func ==(lhs: Line, rhs: Line) -> Bool {

return lhs.color == rhs.color && lhs.width == rhs.width

}

struct Rectangle: Shape, Line {

var size: CGSize

override var bounds: CGSize { return size } // Implements Shape.bounds
override var description: String { return "Rectangle(shape: x:
\(Shape.super.description), Line: \(Line.super.description))"

}

func ==(lhs: Rectangle, rhs: Rectangle) -> Bool {

return (lhs as Shape) == (rhs as Shape) && (lhs as Line) == (rhs as Line)

}

Extra possible improvement. Add a section about resolving a conflict
arising from multiple definitions. My suggestion is to mimic the `A.super`
syntax used for calling initializers:

mixin A { var x = 0 }

mixin B { var x = 1 }
mixin C : A, B { override var x = A.super.x } // OK, conflict
resolved because x overridden

The addition of the `A.super.x` syntax isn't strictly necessary since you
could write `(self as A).x`, but I prefer `A.super.x`.

···

On 1 March 2016 at 05:51, Антон Жилин <swift-evolution@swift.org> wrote:

2016-02-29 4:07 GMT+03:00 Step C <schristopher@bignerdranch.com>:

Sorry, I understood "that phrase" to mean what I just stated.

On Feb 28, 2016, at 8:03 PM, Step C <schristopher@bignerdranch.com> >> wrote:

I understood him to mean that abstract classes cannot be used for value
types, but it would be natural to want that functionality. Mixins would
provide that capability for value types as well as classes.

On Feb 28, 2016, at 7:41 PM, Trent Nadeau <tanadeau@gmail.com> wrote:

The quoted portion of the proposal below doesn't make any sense to me.
Subclasses can't be value types. Do you mean the structs could have similar
functionality?

Firstly, only classes can inherit from such abstract classes, while it
can be easily seen that some subclasses ofCachingSerializable or
SignalSender would naturally have value semantics (be structs, in other
words).

On Sun, Feb 28, 2016 at 5:03 PM, Антон Жилин <swift-evolution@swift.org> >> wrote:

Link to the proposal:
mixins-draft.md · GitHub

2016-02-29 0:56 GMT+03:00 Step C <schristopher@bignerdranch.com>:

It would be helpful if you include the new draft. Or at least a link to
it.

> On Feb 28, 2016, at 3:30 PM, Антон Жилин via swift-evolution < >>>> swift-evolution@swift.org> wrote:
>
> I have rewritten almost the whole proposal in the last 10 hours. I
encourage everyone interested to reread it and suggest fixes, improvements,
as well as new directions for discussion.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Trent Nadeau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I'm prepairing to create a pull request, so I moved the proposal from Gist to my fork of swift-evolution.
Link to the proposal new and hopefully final home:
https://github.com/Anton3/swift-evolution/blob/mixins/proposals/NNNN-mixins.md

I'm -1 to the proposal as written and will try to explain that.

Regarding mixin inheritance:

Problem of members with same signatures inherited from two different places results in compile error.

This is unfortunate as there exists a simple solution for this problem in statically typed languages (more on that later).

Diamond problem is solved by keeping only one copy of mixins mixed-in in the final struct/class.
It works as if bodies of all mixins indirectly mixed-in into D were merged directly into D

That is not a good solution but just a workaround. It probably has origins in dynamically typed languages where a proper solution is not possible (see below).

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.
Let's start with protocol oriented programming (POP). This is a term coined by Dave Abrahams in his great talk at WWDC 2015. The only problem IMO is that POP is nothing new. It is just good old interface oriented programming as has been possible in Java for a long time (the new thing Swift brought to the table is first class value semantics). Actually if you look closely at Dave's talk is not about POP vs. OOP it is about Multiple Inheritance Done Right (TM) vs. single inheritance (with a smattering of value objects).
And protocols in Swift have just the same motivation like interfaces in Java (for the moment disregarding value types): they are classes without state because people thought that the dreaded diamond problem is about state and they thought that if dropping state would make multiple inheritance possible.
That's true to some extent. But actually the diamond problem is not about state. State is only where it surfaces more easily.

Actually the diamond problem is about inheriting a member with the same name (or signature) twice. And that is relevant for protocols as well.
And the beauty is that the solution is the same for state as for members.
So, what is the problem? It is as follows:

GENERAL DIAMOND PROBLEM: When a subclass inherits a member with the same name twice we have to know whether both inherited members have the same semantics.

(A) If both have the same semantics then we only want to use one implementation slot, so we either choose a preferred one from the parents or we implement the method in the subclass and are free to call one or both super implementations or replace their logic with something new. What we do is defined in the subclass.
In case of storage we don't have to do anything, the state is merged automatically (i.e. there will be only one storage slot).

(B) If both have different semantics we want to differentiate between both implementations or storage slots. For that we have to rename one or both in the subclass so they don't clash anymore. When using an instance of the subclass with a static type of one of its parents the original name is used of course in the type i.e. at the call site but the correct renamed one is used internally. Which one is clear as that is given by the static type used.
If a (possibly renamed) member has been abstract it remains abstract unless implemented in the subclass. Of course I can still override a member in the subclass even if it was renamed.

The classical diamond problem will in most cases fall into category (A), i.e. both inherited members have the same semantics and therefore only one storage slot ist used. In some cases we might want to duplicate the storage slot but this implies different semantics, so (B) applies and renaming solves this quite nicely, thereby making the different semantics clear by the now different names.

Addendum: in the diamond case we have to `select` one of both members to be used when accessed through the top type.

Bertrand Meyer's Eiffel demonstrates this solution quite nicely and successfully and that's why there are no interfaces in Eiffel, just classes. Because interfaces are not needed if classes use multiple inheritance. Just add abstract methods and you are done. No need to introduce new concepts.

See Multiple inheritance - Eiffel Software - The Home of EiffelStudio
and ET: Inheritance (for the details)

EXAMPLE 1: (from the Eiffel webpages, renaming syntax to be bikeshedded)

class Array {
  var count: Int
}
class List {
  var count: Int
}
class ArrayList : Array renaming count to capacity, List renaming count to size { ... }

// ArrayList exposes the renamed members only under their new name
let arrayList: ArrayList = ...
arrayList.size // ok, answers the count as inherited from List
arrayList.capacity // ok, answers the count as inherited from Array
arrayList.count // error: undefined `count`

// The original names must still be accessible from the parent types, e.g. Array
let array: Array = arrayList
array.count // ok, answers the count as inherited from Array (= arrayList.capacity)
array.capacity // error: undefined `capacity`

EXAMPLE 2: (from the Eiffel webpages, renaming syntax to be bikeshedded)

class UniversityPerson {
  var computerAccount: Account
}
class Teacher : UniversityPerson { ... }
class Student : UniversityPerson { ... }
class TeachingAssistant :
  Teacher renaming computerAccount to facultyAccount select facultyAccount,
  Student renaming computerAccount to studentAccount {
  ...
}

let assistant: TeachingAssistant = ...
assistant.facultyAccount // ok
assistant.studentAccount // ok
assistant.computerAccount // error: undefined `computerAccount`

let teacher: Teacher = assistant
teacher.computerAccount // ok (= assistant.facultyAccount)

let student: Student = assistant
student.computerAccount // ok (= assistant.studentAccount)

let universityPerson: UniversityPerson = assistant
universityPerson.computerAccount // ok (= assistant.facultyAccount, due to `select`)

Dynamically typed languages like Ruby cannot use this solution because it is not possible to map a call being made by using a parent type (Array in the example) to the renamed member implementation (Array.count -> ArrayList.capacity) as there are no types and it would not be clear whether array.count would need to call `capacity` or `size`. So renaming is not a possibility in dynamically typed languages which is why they resort to workarounds.

So in essence interfaces or protocols aren't needed at all if multiple inheritance is done right.
Citing from the Eiffel web pages: "Some O-O languages support only the two extremes: fully effective classes, and fully deferred "interfaces", but not classes with a mix of effective and deferred features. This is an unacceptable limitation, negating the object-oriented method's support for a seamless, continuous spectrum from the most abstract to the most concrete."

Now we come back to value types in Swift (which are a great thing!). Why do we need protocols for value objects or rather why is inheritance not allowed for them (because if it was and if multiple inheritance was done right no protocols would be needed)?
AFAIU and I might be very wrong here, inheritance is not allowed for value types because we want to embed value types within other value types (e.g. arrays but other structs as well) without having to use references.
But if a value subtype would have added some state an object of that subtype would require more memory than an object of its parent type which is not possible.
The solution is to forbid inheriting state. And what is commonly used for inheritance without state? Right, interfaces, a.k.a. protocols.

Another solution would have been to just forbid inheriting from a class with state. But that ship has sailed a long time ago, I fear, and protocols add another variety of generics into the language feature mix which offers some nice advantages (while having some disadvantages as well, but that is another topic and there are solutions for that as well).

TL;DR

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

What does that mean for the proposals currently being discussed (Mixins, abstract classes)?
- I think we should NOT add mixins with less than full multiple inheritance.
- We should extend protocols to support real multiple inheritance with renaming
- An open question is whether we should extend protocols to support state and what to do with classes in that case (maybe reduce them to implementation inheritance and having types defined solely by protocols; this would enable classes to use their own namespace different from the namespace of types and get rid of the problem of Collection vs. CollectionImpl or CollectionType vs. Collection).

DREAM

In an ideal world we would just have classes with multiple inheritance and abstract methods and would be able to mark classes as value types which would make them have value semantics like current Swift structs. If subclasses of value types introduce additional state they do not conform to their parent but start a new virtual root in the inheritance tree, i.e.

abstract class Vector<N: Number> {
  func +(lhs: Self, rhs: Self) -> Self
  func *(lhs: N, rhs: Self) -> Self
}
value class Vec2d<N: Number> : Vector<N> {
  var x: N
  var y: N
}
value class Vec3d<N: Number> : Vec2d<N> {
  var z: N
}
var v2: Vec2d<Float> = ...
var v3: Vec3d<Float> = ...
var v: Vector<Float>
v = v2 // ok
v = v3 // ok
v2 = v3 // type error: Vec3d is not a subtype of Vec2d

For generics I would use both variants that Swift currently supports, i.e. explicit type parameters and associated types, freely combinable.
Just dreaming... sigh.

-Thorsten

···

Am 29.02.2016 um 19:51 schrieb Антон Жилин via swift-evolution <swift-evolution@swift.org>:

Nicely put.

-Matt

···

On Feb 29, 2016, at 20:55, Jeremy W. Sherman via swift-evolution <swift-evolution@swift.org> wrote:

What could we accomplish with before advice on viewDidLoad? Would this solve any thorny problems we have now? Might adding aspect oriented programming features to protocols avoid the sticky issue of stored properties while neatly solving real problems?

I don't know the answers, but feel a convincing proposal will speak to how it will solve problems, while a truly wondrous proposal will relieve me of burthens I didn't even know I had been shouldering all this time.

@Thorsten,

I don't get why you voted -1, it seems like all you want to add is the
ability to rename in case of classes as an alternative to redefine which
the proposal currently provides. Why not vote +1 and say expand to include
renaming?

Your second point that all you need is a class is also true. The mixing as
proposed could subsume structs and protocols. Though not classes because
they are passed by reference wagers structs are passed by copy. But again
that could be an expansion: expand structs so that they behave like
mixing/traits and allow classes to inherit from structs.

-- Howard.

  -- Howard.

···

On 2 March 2016 at 09:09, Thorsten Seitz via swift-evolution < swift-evolution@swift.org> wrote:

> Am 29.02.2016 um 19:51 schrieb Антон Жилин via swift-evolution < > swift-evolution@swift.org>:
>
> I'm prepairing to create a pull request, so I moved the proposal from
Gist to my fork of swift-evolution.
> Link to the proposal new and hopefully final home:
>
https://github.com/Anton3/swift-evolution/blob/mixins/proposals/NNNN-mixins.md

I'm -1 to the proposal as written and will try to explain that.

Regarding mixin inheritance:

> Problem of members with same signatures inherited from two different
places results in compile error.

This is unfortunate as there exists a simple solution for this problem in
statically typed languages (more on that later).

> Diamond problem is solved by keeping only one copy of mixins mixed-in in
the final struct/class.
> It works as if bodies of all mixins indirectly mixed-in into D were
merged directly into D

That is not a good solution but just a workaround. It probably has origins
in dynamically typed languages where a proper solution is not possible (see
below).

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.
Let's start with protocol oriented programming (POP). This is a term
coined by Dave Abrahams in his great talk at WWDC 2015. The only problem
IMO is that POP is nothing new. It is just good old interface oriented
programming as has been possible in Java for a long time (the new thing
Swift brought to the table is first class value semantics). Actually if you
look closely at Dave's talk is not about POP vs. OOP it is about Multiple
Inheritance Done Right (TM) vs. single inheritance (with a smattering of
value objects).
And protocols in Swift have just the same motivation like interfaces in
Java (for the moment disregarding value types): they are classes without
state because people thought that the dreaded diamond problem is about
state and they thought that if dropping state would make multiple
inheritance possible.
That's true to some extent. But actually the diamond problem is not about
state. State is only where it surfaces more easily.

Actually the diamond problem is about inheriting a member with the same
name (or signature) twice. And that is relevant for protocols as well.
And the beauty is that the solution is the same for state as for members.
So, what is the problem? It is as follows:

GENERAL DIAMOND PROBLEM: When a subclass inherits a member with the same
name twice we have to know whether both inherited members have the same
semantics.

(A) If both have the same semantics then we only want to use one
implementation slot, so we either choose a preferred one from the parents
or we implement the method in the subclass and are free to call one or both
super implementations or replace their logic with something new. What we do
is defined in the subclass.
In case of storage we don't have to do anything, the state is merged
automatically (i.e. there will be only one storage slot).

(B) If both have different semantics we want to differentiate between both
implementations or storage slots. For that we have to rename one or both in
the subclass so they don't clash anymore. When using an instance of the
subclass with a static type of one of its parents the original name is used
of course in the type i.e. at the call site but the correct renamed one is
used internally. Which one is clear as that is given by the static type
used.
If a (possibly renamed) member has been abstract it remains abstract
unless implemented in the subclass. Of course I can still override a member
in the subclass even if it was renamed.

The classical diamond problem will in most cases fall into category (A),
i.e. both inherited members have the same semantics and therefore only one
storage slot ist used. In some cases we might want to duplicate the storage
slot but this implies different semantics, so (B) applies and renaming
solves this quite nicely, thereby making the different semantics clear by
the now different names.

Addendum: in the diamond case we have to `select` one of both members to
be used when accessed through the top type.

Bertrand Meyer's Eiffel demonstrates this solution quite nicely and
successfully and that's why there are no interfaces in Eiffel, just
classes. Because interfaces are not needed if classes use multiple
inheritance. Just add abstract methods and you are done. No need to
introduce new concepts.

See Multiple inheritance - Eiffel Software - The Home of EiffelStudio
and
ET: Inheritance
(for the details)

EXAMPLE 1: (from the Eiffel webpages, renaming syntax to be bikeshedded)

class Array {
        var count: Int
}
class List {
        var count: Int
}
class ArrayList : Array renaming count to capacity, List renaming count to
size { ... }

// ArrayList exposes the renamed members only under their new name
let arrayList: ArrayList = ...
arrayList.size // ok, answers the count as inherited from List
arrayList.capacity // ok, answers the count as inherited from Array
arrayList.count // error: undefined `count`

// The original names must still be accessible from the parent types, e.g.
Array
let array: Array = arrayList
array.count // ok, answers the count as inherited from Array (=
arrayList.capacity)
array.capacity // error: undefined `capacity`

EXAMPLE 2: (from the Eiffel webpages, renaming syntax to be bikeshedded)

class UniversityPerson {
        var computerAccount: Account
}
class Teacher : UniversityPerson { ... }
class Student : UniversityPerson { ... }
class TeachingAssistant :
        Teacher renaming computerAccount to facultyAccount select
facultyAccount,
        Student renaming computerAccount to studentAccount {
        ...
}

let assistant: TeachingAssistant = ...
assistant.facultyAccount // ok
assistant.studentAccount // ok
assistant.computerAccount // error: undefined `computerAccount`

let teacher: Teacher = assistant
teacher.computerAccount // ok (= assistant.facultyAccount)

let student: Student = assistant
student.computerAccount // ok (= assistant.studentAccount)

let universityPerson: UniversityPerson = assistant
universityPerson.computerAccount // ok (= assistant.facultyAccount, due to
`select`)

Dynamically typed languages like Ruby cannot use this solution because it
is not possible to map a call being made by using a parent type (Array in
the example) to the renamed member implementation (Array.count ->
ArrayList.capacity) as there are no types and it would not be clear whether
array.count would need to call `capacity` or `size`. So renaming is not a
possibility in dynamically typed languages which is why they resort to
workarounds.

So in essence interfaces or protocols aren't needed at all if multiple
inheritance is done right.
Citing from the Eiffel web pages: "Some O-O languages support only the two
extremes: fully effective classes, and fully deferred "interfaces", but not
classes with a mix of effective and deferred features. This is an
unacceptable limitation, negating the object-oriented method's support for
a seamless, continuous spectrum from the most abstract to the most
concrete."

Now we come back to value types in Swift (which are a great thing!). Why
do we need protocols for value objects or rather why is inheritance not
allowed for them (because if it was and if multiple inheritance was done
right no protocols would be needed)?
AFAIU and I might be very wrong here, inheritance is not allowed for value
types because we want to embed value types within other value types (e.g.
arrays but other structs as well) without having to use references.
But if a value subtype would have added some state an object of that
subtype would require more memory than an object of its parent type which
is not possible.
The solution is to forbid inheriting state. And what is commonly used for
inheritance without state? Right, interfaces, a.k.a. protocols.

Another solution would have been to just forbid inheriting from a class
with state. But that ship has sailed a long time ago, I fear, and protocols
add another variety of generics into the language feature mix which offers
some nice advantages (while having some disadvantages as well, but that is
another topic and there are solutions for that as well).

TL;DR

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

What does that mean for the proposals currently being discussed (Mixins,
abstract classes)?
- I think we should NOT add mixins with less than full multiple
inheritance.
- We should extend protocols to support real multiple inheritance with
renaming
- An open question is whether we should extend protocols to support state
and what to do with classes in that case (maybe reduce them to
implementation inheritance and having types defined solely by protocols;
this would enable classes to use their own namespace different from the
namespace of types and get rid of the problem of Collection vs.
CollectionImpl or CollectionType vs. Collection).

DREAM

In an ideal world we would just have classes with multiple inheritance and
abstract methods and would be able to mark classes as value types which
would make them have value semantics like current Swift structs. If
subclasses of value types introduce additional state they do not conform to
their parent but start a new virtual root in the inheritance tree, i.e.

abstract class Vector<N: Number> {
        func +(lhs: Self, rhs: Self) -> Self
        func *(lhs: N, rhs: Self) -> Self
}
value class Vec2d<N: Number> : Vector<N> {
        var x: N
        var y: N
}
value class Vec3d<N: Number> : Vec2d<N> {
        var z: N
}
var v2: Vec2d<Float> = ...
var v3: Vec3d<Float> = ...
var v: Vector<Float>
v = v2 // ok
v = v3 // ok
v2 = v3 // type error: Vec3d is not a subtype of Vec2d

For generics I would use both variants that Swift currently supports, i.e.
explicit type parameters and associated types, freely combinable.
Just dreaming... sigh.

-Thorsten

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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 the position and
speed of each, and let that be where the `move` functionality operates (or
the type that a `move` func operates on).

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

···

On Tue, Mar 1, 2016 at 5:25 PM, Howard Lovatt via swift-evolution < swift-evolution@swift.org> wrote:

@Thorsten,

I don't get why you voted -1, it seems like all you want to add is the
ability to rename in case of classes as an alternative to redefine which
the proposal currently provides. Why not vote +1 and say expand to include
renaming?

Your second point that all you need is a class is also true. The mixing as
proposed could subsume structs and protocols. Though not classes because
they are passed by reference wagers structs are passed by copy. But again
that could be an expansion: expand structs so that they behave like
mixing/traits and allow classes to inherit from structs.

-- Howard.

  -- Howard.

On 2 March 2016 at 09:09, Thorsten Seitz via swift-evolution < > swift-evolution@swift.org> wrote:

> Am 29.02.2016 um 19:51 schrieb Антон Жилин via swift-evolution < >> swift-evolution@swift.org>:
>
> I'm prepairing to create a pull request, so I moved the proposal from
Gist to my fork of swift-evolution.
> Link to the proposal new and hopefully final home:
>
https://github.com/Anton3/swift-evolution/blob/mixins/proposals/NNNN-mixins.md

I'm -1 to the proposal as written and will try to explain that.

Regarding mixin inheritance:

> Problem of members with same signatures inherited from two different
places results in compile error.

This is unfortunate as there exists a simple solution for this problem in
statically typed languages (more on that later).

> Diamond problem is solved by keeping only one copy of mixins mixed-in
in the final struct/class.
> It works as if bodies of all mixins indirectly mixed-in into D were
merged directly into D

That is not a good solution but just a workaround. It probably has
origins in dynamically typed languages where a proper solution is not
possible (see below).

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.
Let's start with protocol oriented programming (POP). This is a term
coined by Dave Abrahams in his great talk at WWDC 2015. The only problem
IMO is that POP is nothing new. It is just good old interface oriented
programming as has been possible in Java for a long time (the new thing
Swift brought to the table is first class value semantics). Actually if you
look closely at Dave's talk is not about POP vs. OOP it is about Multiple
Inheritance Done Right (TM) vs. single inheritance (with a smattering of
value objects).
And protocols in Swift have just the same motivation like interfaces in
Java (for the moment disregarding value types): they are classes without
state because people thought that the dreaded diamond problem is about
state and they thought that if dropping state would make multiple
inheritance possible.
That's true to some extent. But actually the diamond problem is not about
state. State is only where it surfaces more easily.

Actually the diamond problem is about inheriting a member with the same
name (or signature) twice. And that is relevant for protocols as well.
And the beauty is that the solution is the same for state as for members.
So, what is the problem? It is as follows:

GENERAL DIAMOND PROBLEM: When a subclass inherits a member with the same
name twice we have to know whether both inherited members have the same
semantics.

(A) If both have the same semantics then we only want to use one
implementation slot, so we either choose a preferred one from the parents
or we implement the method in the subclass and are free to call one or both
super implementations or replace their logic with something new. What we do
is defined in the subclass.
In case of storage we don't have to do anything, the state is merged
automatically (i.e. there will be only one storage slot).

(B) If both have different semantics we want to differentiate between
both implementations or storage slots. For that we have to rename one or
both in the subclass so they don't clash anymore. When using an instance of
the subclass with a static type of one of its parents the original name is
used of course in the type i.e. at the call site but the correct renamed
one is used internally. Which one is clear as that is given by the static
type used.
If a (possibly renamed) member has been abstract it remains abstract
unless implemented in the subclass. Of course I can still override a member
in the subclass even if it was renamed.

The classical diamond problem will in most cases fall into category (A),
i.e. both inherited members have the same semantics and therefore only one
storage slot ist used. In some cases we might want to duplicate the storage
slot but this implies different semantics, so (B) applies and renaming
solves this quite nicely, thereby making the different semantics clear by
the now different names.

Addendum: in the diamond case we have to `select` one of both members to
be used when accessed through the top type.

Bertrand Meyer's Eiffel demonstrates this solution quite nicely and
successfully and that's why there are no interfaces in Eiffel, just
classes. Because interfaces are not needed if classes use multiple
inheritance. Just add abstract methods and you are done. No need to
introduce new concepts.

See Multiple inheritance - Eiffel Software - The Home of EiffelStudio
and
ET: Inheritance
(for the details)

EXAMPLE 1: (from the Eiffel webpages, renaming syntax to be bikeshedded)

class Array {
        var count: Int
}
class List {
        var count: Int
}
class ArrayList : Array renaming count to capacity, List renaming count
to size { ... }

// ArrayList exposes the renamed members only under their new name
let arrayList: ArrayList = ...
arrayList.size // ok, answers the count as inherited from List
arrayList.capacity // ok, answers the count as inherited from Array
arrayList.count // error: undefined `count`

// The original names must still be accessible from the parent types,
e.g. Array
let array: Array = arrayList
array.count // ok, answers the count as inherited from Array (=
arrayList.capacity)
array.capacity // error: undefined `capacity`

EXAMPLE 2: (from the Eiffel webpages, renaming syntax to be bikeshedded)

class UniversityPerson {
        var computerAccount: Account
}
class Teacher : UniversityPerson { ... }
class Student : UniversityPerson { ... }
class TeachingAssistant :
        Teacher renaming computerAccount to facultyAccount select
facultyAccount,
        Student renaming computerAccount to studentAccount {
        ...
}

let assistant: TeachingAssistant = ...
assistant.facultyAccount // ok
assistant.studentAccount // ok
assistant.computerAccount // error: undefined `computerAccount`

let teacher: Teacher = assistant
teacher.computerAccount // ok (= assistant.facultyAccount)

let student: Student = assistant
student.computerAccount // ok (= assistant.studentAccount)

let universityPerson: UniversityPerson = assistant
universityPerson.computerAccount // ok (= assistant.facultyAccount, due
to `select`)

Dynamically typed languages like Ruby cannot use this solution because it
is not possible to map a call being made by using a parent type (Array in
the example) to the renamed member implementation (Array.count ->
ArrayList.capacity) as there are no types and it would not be clear whether
array.count would need to call `capacity` or `size`. So renaming is not a
possibility in dynamically typed languages which is why they resort to
workarounds.

So in essence interfaces or protocols aren't needed at all if multiple
inheritance is done right.
Citing from the Eiffel web pages: "Some O-O languages support only the
two extremes: fully effective classes, and fully deferred "interfaces", but
not classes with a mix of effective and deferred features. This is an
unacceptable limitation, negating the object-oriented method's support for
a seamless, continuous spectrum from the most abstract to the most
concrete."

Now we come back to value types in Swift (which are a great thing!). Why
do we need protocols for value objects or rather why is inheritance not
allowed for them (because if it was and if multiple inheritance was done
right no protocols would be needed)?
AFAIU and I might be very wrong here, inheritance is not allowed for
value types because we want to embed value types within other value types
(e.g. arrays but other structs as well) without having to use references.
But if a value subtype would have added some state an object of that
subtype would require more memory than an object of its parent type which
is not possible.
The solution is to forbid inheriting state. And what is commonly used for
inheritance without state? Right, interfaces, a.k.a. protocols.

Another solution would have been to just forbid inheriting from a class
with state. But that ship has sailed a long time ago, I fear, and protocols
add another variety of generics into the language feature mix which offers
some nice advantages (while having some disadvantages as well, but that is
another topic and there are solutions for that as well).

TL;DR

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

What does that mean for the proposals currently being discussed (Mixins,
abstract classes)?
- I think we should NOT add mixins with less than full multiple
inheritance.
- We should extend protocols to support real multiple inheritance with
renaming
- An open question is whether we should extend protocols to support state
and what to do with classes in that case (maybe reduce them to
implementation inheritance and having types defined solely by protocols;
this would enable classes to use their own namespace different from the
namespace of types and get rid of the problem of Collection vs.
CollectionImpl or CollectionType vs. Collection).

DREAM

In an ideal world we would just have classes with multiple inheritance
and abstract methods and would be able to mark classes as value types which
would make them have value semantics like current Swift structs. If
subclasses of value types introduce additional state they do not conform to
their parent but start a new virtual root in the inheritance tree, i.e.

abstract class Vector<N: Number> {
        func +(lhs: Self, rhs: Self) -> Self
        func *(lhs: N, rhs: Self) -> Self
}
value class Vec2d<N: Number> : Vector<N> {
        var x: N
        var y: N
}
value class Vec3d<N: Number> : Vec2d<N> {
        var z: N
}
var v2: Vec2d<Float> = ...
var v3: Vec3d<Float> = ...
var v: Vector<Float>
v = v2 // ok
v = v3 // ok
v2 = v3 // type error: Vec3d is not a subtype of Vec2d

For generics I would use both variants that Swift currently supports,
i.e. explicit type parameters and associated types, freely combinable.
Just dreaming... sigh.

-Thorsten

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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.

Yes, that is exactly the point of Eiffel-style-multiple inheritance.

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?

No, functions that expect Ps or Qs will talk the language of P and Q. They don't have to know about renaming (that's the whole point which is only possible in statically typed languages).
Functions that expect C will have to know about renaming. They will talk the language of C.

-Thorsten

···

Am 02.03.2016 um 02:00 schrieb Brian Pratt <brian@pratt.io>:

On "traits vs mixins",
I tend to agree with Patrick Gili that probably the most important
difference between traits and mixins is that mixins define state. This
article agrees:
http://matthijshollemans.com/2015/07/22/mixins-and-traits-in-swift-2/

On initializers,
Initializers really only make sense on fully defined types. That's why I
disallowed implicit initializer inheritance. But I believe that "helpers",
which know how to initialize their part of state, can be useful.

On mixin conflicts resolving,
I agree that this question should be solved not in "future directions", but
within the proposal itself. "Merge members" and "keep copies for both super
mixins" are equal alternate options.
We need to decide on syntax. I also don't fully understand how it should
work, question below.

A special thanks ot Thorsten Seitz for opening my eyes on problems in Swift
type system. I agree with "dream" part completely. But I'm afraid, that
already can't be changed.

New set of questions:

1. Can a mixin contain uninitialized state, unlike fully defined types?
Example:

mixin A { var x: Int }
struct B: A { init(x: Int) { self.x = x } }

2. What should be syntax for conflict resolution? I will use the following
in this post:

var x = A.x
func f() = A.f

The intent here should be to use existing Swift constructs.

3. If we decide to keep two copies in a conflict, do we need to rename all
members, or can we rename selectively? Example:

mixin A {
  var x: Int = 0
  func show() { print(x) }
}
mixin B {
  var x: Int = 1
  func show() { print(x) }
}
struct S: A, B {
  var y = A.x
  var z = B.x
  // nothing touching show()
}
let s = S()
s.show() //=> 0 or 1?

This example could also be formulated for problem A -> (B,C) -> D

4. Should we allow for arbitrary renaming of members in subtypes, not only
in conflicts?

5. Should we allow conflicting inherited members until usage or throw an
error immediately?

mixin A { var x: Int = 0 }
mixin B { var x: Int = 1 }
struct C: A, B { func show() { print(A.x); print(B.x) } }
let c = C() // error??
C().show() //=> 01
C().x // error: "x is a conflicting member in C, cannot be called here"
C().A.x // syntax error

···

2016-03-02 8:37 GMT+03:00 Thorsten Seitz <tseitz42@icloud.com>:

> Am 02.03.2016 um 02:00 schrieb Brian Pratt <brian@pratt.io>:
>
> 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.

Yes, that is exactly the point of Eiffel-style-multiple inheritance.

> 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?

No, functions that expect Ps or Qs will talk the language of P and Q. They
don't have to know about renaming (that's the whole point which is only
possible in statically typed languages).
Functions that expect C will have to know about renaming. They will talk
the language of C.

-Thorsten