<html><body><div><br>Am 02. März 2016 um 10:55 schrieb Антон Жилин &lt;antonyzhilin@gmail.com&gt;:<br><br><div><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div>On "traits vs mixins",<br></div><div>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:&nbsp;<a href="http://matthijshollemans.com/2015/07/22/mixins-and-traits-in-swift-2/" data-mce-href="http://matthijshollemans.com/2015/07/22/mixins-and-traits-in-swift-2/">http://matthijshollemans.com/2015/07/22/mixins-and-traits-in-swift-2/</a><br data-mce-bogus="1"></div><div><br></div><div>On initializers,</div><div>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.</div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>I think we should allow for a mixin to be fully responsible for its state (which might be private). Therefore initialization should be possible.<br></span></div><div><span><br data-mce-bogus="1"></span></div><div><span><br></span><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div></div><div>On mixin conflicts resolving,</div><div>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.</div><div>We need to decide on syntax. I also don't fully understand how it should work, question below.</div><div><br></div><div>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.</div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>Thanks! I'm glad that I'm not alone :-)</span></div><div><span><br data-mce-bogus="1"></span></div><div><span> <br></span><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div></div><div>New set of questions:</div><div><br></div><div>1. Can a mixin contain uninitialized state, unlike fully defined types? Example:</div><div><br></div><div>mixin A { var x: Int }</div><div>struct B: A { init(x: Int) { self.x = x } }</div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>If such a mixin would be marked as "abstract" that should be no problem.</span></div><div><span><br data-mce-bogus="1"></span></div><div><span> <br></span><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div></div><div>2. What should be syntax for conflict resolution? I will use the following in this post:</div><div><br></div><div>var x = A.x</div><div>func f() = A.f</div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>While that syntax looks very concise "var y = A.x" does not convey very good that y replaces x in the new type. But let's stay with that syntax for the moment as we can bikeshed that later.<br></span></div><div><span><br data-mce-bogus="1"></span></div><div><span><br></span><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div></div><div>The intent here should be to use existing Swift constructs.</div><div><br></div><div>3. If we decide to keep two copies in a conflict, do we need to rename all members, or can we rename selectively? Example:</div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>Each conflict has to be solved by itself, independently from all other conflicts, but all conflicts have to be solved one way or the other.</span></div><div><br data-mce-bogus="1"></div><div><span><br></span><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div></div><div>mixin A {</div><div><div>&nbsp; var x: Int = 0</div>&nbsp; func show() { print(x) }<div>}</div><div>mixin B {</div><div>&nbsp; var x: Int = 1</div>&nbsp; func show() { print(x) }<div>}</div><div>struct S: A, B {</div><div>&nbsp; var y = A.x</div><div>&nbsp; var z = B.x</div><div>&nbsp; // nothing touching show()</div><div>}<div><div>let s = S()</div><div>s.show() &nbsp;//=&gt; 0 or 1?</div></div></div></div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>show() is in conflict which has to be solved. Either by (a) renaming one or both to get two copies or by (b) selecting one implementation.</span></div><div><span><br data-mce-bogus="1"></span></div><div><span>Example using choice (b):<br data-mce-bogus="1"></span></div><div><span><br data-mce-bogus="1"></span></div><div><span>struct S: A, B {<br data-mce-bogus="1"></span></div><div><span>&nbsp; var y = A.x<br data-mce-bogus="1"></span></div><div><span>&nbsp; var z = B.x<br data-mce-bogus="1"></span></div><div><span>&nbsp; func show() = A.show &nbsp;&nbsp; // selecting implementation of A<br data-mce-bogus="1"></span></div><div><span>}</span></div><div><span>let s = S()<br data-mce-bogus="1"></span></div><div><span>s.show()&nbsp;&nbsp; //=&gt; 0, because the implementation of A was chosen and A.show uses A.x<br data-mce-bogus="1"></span></div><div><span><br data-mce-bogus="1"></span></div><div><span><br data-mce-bogus="1"></span></div><div><span>If I had chosen B.show in the definition of struct S, the result would have been 1.<br data-mce-bogus="1"></span></div><div><span><br data-mce-bogus="1"></span></div><div><span><br></span><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div><div></div>This example could also be formulated for problem A -&gt; (B,C) -&gt; D</div><div><br></div><div>4. Should we allow for arbitrary renaming of members in subtypes, not only in conflicts?</div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>Eiffel does so which can be nice, e.g.</span></div><div><span><br data-mce-bogus="1"></span></div><div><span>struct Stack : List {</span></div><div><span>&nbsp;&nbsp;&nbsp; func pop() = List.removeFirst()</span></div><div><span>&nbsp;&nbsp;&nbsp; func peek() = List.first()<br data-mce-bogus="1"></span></div><div><span>}</span></div><div><span><br data-mce-bogus="1"></span></div><div><span>This is not that important, though, and can easily be added later. The semantics for renaming stay completely unchanged.<br></span></div><div><span><br data-mce-bogus="1"></span></div><div><span><br></span><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div></div><div>5. Should we allow conflicting inherited members until usage or throw an error immediately?</div><div><br></div><div><div>mixin A { var x: Int = 0 }</div><div>mixin B { var x: Int = 1 }</div><div>struct C: A, B { func show() { print(A.x); print(B.x) } }</div></div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>Actually the error is in the definition of struct C and should be flagged there: "x is a conflicting member in C,&nbsp; either rename x or select one of A.x or B.x"</span></div><div><span><br data-mce-bogus="1"></span></div><div><span><br></span><blockquote type="cite"><div class="msg-quote"><div dir="ltr"><div><div></div><div>let c = C() &nbsp;// error??</div><div>C().show() &nbsp;//=&gt; 01</div><div>C().x &nbsp;// error: "x is a conflicting member in C, cannot be called here"</div></div><div>C().A.x &nbsp;// syntax error</div></div></div></blockquote></div><div><span><br data-mce-bogus="1"></span></div><div><span>These are all too late.<br></span></div><div><span><br data-mce-bogus="1"></span></div><div><span>-Thorsten<br data-mce-bogus="1"></span></div><div><span><br data-mce-bogus="1"></span></div><div><span><br data-mce-bogus="1"></span></div><div><span> <br></span><blockquote type="cite"><div class="msg-quote"><div class="gmail_extra">2016-03-02 8:37 GMT+03:00 Thorsten Seitz <span dir="ltr">&lt;<a href="mailto:tseitz42@icloud.com" data-mce-href="mailto:tseitz42@icloud.com">tseitz42@icloud.com</a>&gt;</span>:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0 0 0 0.8ex; border-left: 1px #ccc solid; padding-left: 1ex;" data-mce-style="margin: 0 0 0 0.8ex; border-left: 1px #ccc solid; padding-left: 1ex;"><span class=""><br> &gt; Am 02.03.2016 um 02:00 schrieb Brian Pratt &lt;<a href="mailto:brian@pratt.io" data-mce-href="mailto:brian@pratt.io">brian@pratt.io</a>&gt;:<br> &gt;<br> &gt; 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.<br> <br> </span>Yes, that is exactly the point of Eiffel-style-multiple inheritance.<br> <span class=""><br> &gt; 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?<br> <br> </span>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).<br> Functions that expect C will have to know about renaming. They will talk the language of C.<br> <span class="HOEnZb"><span style="color: #888888;" data-mce-style="color: #888888;" color="#888888"><br> -Thorsten </span></span></blockquote></div><br></div></div></blockquote></div></div></body></html>