[swift-evolution] [Draft] Mixins

Антон Жилин antonyzhilin at gmail.com
Wed Mar 2 03:55:49 CST 2016


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 at icloud.com>:

>
> > Am 02.03.2016 um 02:00 schrieb Brian Pratt <brian at 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160302/b2e5abb4/attachment.html>


More information about the swift-evolution mailing list