digitalmars.D.learn - mixin bug?
- Engine Machine (28/28) Aug 11 2016 template F1(T)
- sldkf (24/52) Aug 11 2016 I don't think it's a bug. F3's bar() doesn't exist yet in F2.
- Engine Machine (20/70) Aug 11 2016 Yes, but when we "mixin" again, bar then does exist. I see the
- =?UTF-8?Q?Ali_=c3=87ehreli?= (7/8) Aug 11 2016 That's the case for string mixins. Template mixins bring a name
- Engine Machine (16/25) Aug 11 2016 "When a mixed-in name is the same as a name that is in the
- sldkf (7/13) Aug 11 2016 You are goind to hit a wall. Template programming is not OOP.
- Engine Machine (38/52) Aug 11 2016 Well, duh, it is not oop, but that doesn't mean it doesn't have
- sldkf (33/35) Aug 12 2016 issue solved using a "template this parameter":
- Engine Machine (16/51) Aug 12 2016 This is not the solution to the original problem.
- sldkf (4/24) Aug 12 2016 No "length" returns 3.
- Engine Machine (5/35) Aug 12 2016 You're right. My mistake. Thanks!
template F1(T) { void bar() { writeln("Bar0"); } } template F2(T) { mixin F1!T; void foo() { bar(); } } template F3(T) { mixin F2!T; void bar() { writeln("Bar1"); } // <- This bar should be used for F2's foo! } struct F4(T) { mixin F3!T; } (Or on can turn F3 in to a struct directly) Then f3.foo() calls bar from F0, not F3's bar! This seems like a big bug! One expects the same behavior of mixins regardless of mixin nesting. While you could argue that foo, when declared, is calling F0's bar, this is not consistent with the view that mixin templates only adds what is not there. I don't like the idea that calls are resolved first come first serve as it means one can't extend templates in a natural logical way.
Aug 11 2016
On Thursday, 11 August 2016 at 17:56:47 UTC, Engine Machine wrote:template F1(T) { void bar() { writeln("Bar0"); } } template F2(T) { mixin F1!T; void foo() { bar(); } } template F3(T) { mixin F2!T; void bar() { writeln("Bar1"); } // <- This bar should be used for F2's foo! } struct F4(T) { mixin F3!T; } (Or on can turn F3 in to a struct directly) Then f3.foo() calls bar from F0, not F3's bar! This seems like a big bug! One expects the same behavior of mixins regardless of mixin nesting. While you could argue that foo, when declared, is calling F0's bar, this is not consistent with the view that mixin templates only adds what is not there. I don't like the idea that calls are resolved first come first serve as it means one can't extend templates in a natural logical way.I don't think it's a bug. F3's bar() doesn't exist yet in F2. Logically F1's one is called. The language allows to alias a mixin so that a particular overload can be called. In you case you can really target F1.bar without problem: °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° template F1(T){void bar() {writeln("Bar0");}} template F2(T) { mixin F1!T FF1; void foo() { FF3.bar; } } template F3(T) { mixin F2!T FF2; void bar() { writeln("Bar1");} } struct F4(T){mixin F3!T FF3;} °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° See https://dlang.org/spec/template-mixin.html#mixin_scope However the specification doesn't say what is the rule that's applied. Even if it look logical that F1.bar() is chosen it has to be written somewhere.
Aug 11 2016
On Thursday, 11 August 2016 at 19:05:58 UTC, sldkf wrote:On Thursday, 11 August 2016 at 17:56:47 UTC, Engine Machine wrote:Yes, but when we "mixin" again, bar then does exist. I see the mixin as a sort of copy and paste. We only paste in what doesn't exist. So the first time bar gets inserted in to F2, but then that bar doesn't get inserted in to F3 because it already exists. Basically a mixin of a mixin is not logically a mixin. That makes no sense to me. A mixin is suppose to behave a certain way, but when we do a mixin of a mixin we get behavior that doesn't behave the same way as a single mixin.template F1(T) { void bar() { writeln("Bar0"); } } template F2(T) { mixin F1!T; void foo() { bar(); } } template F3(T) { mixin F2!T; void bar() { writeln("Bar1"); } // <- This bar should be used for F2's foo! } struct F4(T) { mixin F3!T; } (Or on can turn F3 in to a struct directly) Then f3.foo() calls bar from F0, not F3's bar! This seems like a big bug! One expects the same behavior of mixins regardless of mixin nesting. While you could argue that foo, when declared, is calling F0's bar, this is not consistent with the view that mixin templates only adds what is not there. I don't like the idea that calls are resolved first come first serve as it means one can't extend templates in a natural logical way.I don't think it's a bug. F3's bar() doesn't exist yet in F2. Logically F1's one is called.The language allows to alias a mixin so that a particular overload can be called. In you case you can really target F1.bar without problem:I don't want to target F1.bar, I want foo to target future bar's. It is like overloading, but for templates. If you were doing overloading, and it called the base function instead, it wouldn't be overloading, would it?°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° template F1(T){void bar() {writeln("Bar0");}} template F2(T) { mixin F1!T FF1; void foo() { FF3.bar; } }This requires F2 to know the future. It also forces it to use a specific bar. I want inheritance like logic. Which is what we get when we mixin one deep, but when we go deeper, it breaks. I think this is a bug. It seems like D is trying to resolve things only after each mixin, rather than resolving after all nested mixins are evaluated.
Aug 11 2016
On 08/11/2016 01:27 PM, Engine Machine wrote:I see the mixin as a sort of copy and paste.That's the case for string mixins. Template mixins bring a name resolution scope. My understanding of the topic: http://ddili.org/ders/d.en/mixin.html#ix_mixin.name%20space,%20mixin The spec: https://dlang.org/spec/template-mixin.html Ali
Aug 11 2016
On Thursday, 11 August 2016 at 21:03:36 UTC, Ali Çehreli wrote:On 08/11/2016 01:27 PM, Engine Machine wrote:"When a mixed-in name is the same as a name that is in the surrounding scope, then the name that is in the surrounding scope gets used:" Which is my point, for "2nd order or higher" mixins, this does not occur. The why I see it is that mixin template is sort of like a copy and paste, but only paste if the members do not exist already(i.e., the current behavior for "1st order" mixins. I would expect the same logic to hold for higher order mixins since a mixin of a mixin is still a mixin). I realize why D behaves the way it does, but this is limiting. It simply greedily resolves referencing members rather than lazily. If the greedy method actually has some desired characteristic, then a lazy mixin would be nice. lazy mixin T1!T;I see the mixin as a sort of copy and paste.That's the case for string mixins. Template mixins bring a name resolution scope. My understanding of the topic: http://ddili.org/ders/d.en/mixin.html#ix_mixin.name%20space,%20mixin The spec: https://dlang.org/spec/template-mixin.html Ali
Aug 11 2016
On Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine wrote:This requires F2 to know the future. It also forces it to use a specific bar. I want inheritance like logic.You are goind to hit a wall. Template programming is not OOP. I'm not even sure that reflection would work in order to determine the most "recent" overload.Which is what we get when we mixin one deep, but when we go deeper, it breaks. I think this is a bug. It seems like D is trying to resolve things only after each mixin, rather than resolving after all nested mixins are evaluated.This is the only issue I see: "It seems like D is trying to...". We need to know exactly what D does: https://issues.dlang.org/show_bug.cgi?id=16376.
Aug 11 2016
On Thursday, 11 August 2016 at 21:25:20 UTC, sldkf wrote:On Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine wrote:Well, duh, it is not oop, but that doesn't mean it doesn't have similar abstractions, you need to read between the lines a bit more.This requires F2 to know the future. It also forces it to use a specific bar. I want inheritance like logic.You are goind to hit a wall. Template programming is not OOP. I'm not even sure that reflection would work in order to determine the most "recent" overload.It would be nice if D would bind the function calls lazily, so to speak, that is all I'm saying. This way we can get polymorphic/oop like behavior, if you will. template A(T) { void Bark() { writeln("Ruff Ruff"); } } template B(T) { mixin A!T; void Talk() { Bark(); } } template Duck(T) { mixin B!T; private void Bark() { writeln("Quack"); } } this is a contrived and misleading example if you take it seriously. But Duck.Talk(); should Quack. It would if D resolved Bark from Talk after the final "mixin". (In Duck, not in B). Else we are stuck with a barking duck. What it seems to do is first evaluate the template A!T, then B!T, then Duck!T. Since B!T is evaluated first and plugged in to Duck, Talk is already resolved to use A!T.Bark. Rather, If Duck!T was evaluated first, D would understand that Bark was already defined and when Talk was added, it could have it use the bark defined in duck, rather than A. This, would, of course, require a sort of Duck!T.B!T type, since B!T used inside of Duck would have a different Talk() than if it is not used in Duck. Again, maybe the compiler is just to ignorant to do this as it is complex(might require flow analysis and all that stuff or just be an ill-defined problem in general).Which is what we get when we mixin one deep, but when we go deeper, it breaks. I think this is a bug. It seems like D is trying to resolve things only after each mixin, rather than resolving after all nested mixins are evaluated.This is the only issue I see: "It seems like D is trying to...". We need to know exactly what D does: https://issues.dlang.org/show_bug.cgi?id=16376.
Aug 11 2016
On Friday, 12 August 2016 at 02:09:21 UTC, Engine Machine wrote:On Thursday, 11 August 2016 at 21:25:20 UTC, sldkf wrote:issue solved using a "template this parameter": °°°°°°°°°°°°°°°°°°°°°°°°°°°°°° template Cow() { void soundImpl() { writeln("moo"); } } template Cat() { mixin AnimalSound; void soundImpl() { writeln("meaow"); } } template Duck() { mixin Cat; void soundImpl() { writeln("quack"); } } template AnimalSound() { void emittSound(this T)() { (cast(T) this).soundImpl(); } // would also work with "this.soundImpl()" } struct Animal { mixin Duck; } void main() { Animal a; a.emittSound; } °°°°°°°°°°°°°°°°°°°°°°°°°°°°°° https://dlang.org/spec/template.html#TemplateThisParameterOn Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine
Aug 12 2016
On Friday, 12 August 2016 at 15:35:50 UTC, sldkf wrote:On Friday, 12 August 2016 at 02:09:21 UTC, Engine Machine wrote:This is not the solution to the original problem. template X(T) { int _len = 0; int Length() { return _len; } int length(this T)() { return (cast(T)this).Length(); } } template Y(T) { mixin X!T; int Length() { return 3; } } Then calling length returns 0, while calling Length returns 3. But we obviously want length to "follow" Length, yet it doesn't due to D resolving length in X before it is mixed in Y!T.On Thursday, 11 August 2016 at 21:25:20 UTC, sldkf wrote:issue solved using a "template this parameter": °°°°°°°°°°°°°°°°°°°°°°°°°°°°°° template Cow() { void soundImpl() { writeln("moo"); } } template Cat() { mixin AnimalSound; void soundImpl() { writeln("meaow"); } } template Duck() { mixin Cat; void soundImpl() { writeln("quack"); } } template AnimalSound() { void emittSound(this T)() { (cast(T) this).soundImpl(); } // would also work with "this.soundImpl()" } struct Animal { mixin Duck; } void main() { Animal a; a.emittSound; } °°°°°°°°°°°°°°°°°°°°°°°°°°°°°° https://dlang.org/spec/template.html#TemplateThisParameterOn Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine
Aug 12 2016
On Friday, 12 August 2016 at 23:14:23 UTC, Engine Machine wrote:On Friday, 12 August 2016 at 15:35:50 UTC, sldkf wrote:No "length" returns 3. https://ideone.com/T8HjZl Really, it's there, in front of your eyes.On Friday, 12 August 2016 at 02:09:21 UTC, Engine Machine wrote:This is not the solution to the original problem. template X(T) { int _len = 0; int Length() { return _len; } int length(this T)() { return (cast(T)this).Length(); } } template Y(T) { mixin X!T; int Length() { return 3; } } Then calling length returns 0, while calling Length returns 3. But we obviously want length to "follow" Length, yet it doesn't due to D resolving length in X before it is mixed in Y!T.On Thursday, 11 August 2016 at 21:25:20 UTC, sldkf wrote:On Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine
Aug 12 2016
On Friday, 12 August 2016 at 23:48:54 UTC, sldkf wrote:On Friday, 12 August 2016 at 23:14:23 UTC, Engine Machine wrote:You're right. My mistake. Thanks! Do I have to do this with every function call? Seems a bit tedious to have to add this T to every function and add this. to every call.On Friday, 12 August 2016 at 15:35:50 UTC, sldkf wrote:No "length" returns 3. https://ideone.com/T8HjZl Really, it's there, in front of your eyes.On Friday, 12 August 2016 at 02:09:21 UTC, Engine Machine wrote:This is not the solution to the original problem. template X(T) { int _len = 0; int Length() { return _len; } int length(this T)() { return (cast(T)this).Length(); } } template Y(T) { mixin X!T; int Length() { return 3; } } Then calling length returns 0, while calling Length returns 3. But we obviously want length to "follow" Length, yet it doesn't due to D resolving length in X before it is mixed in Y!T.On Thursday, 11 August 2016 at 21:25:20 UTC, sldkf wrote:On Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine
Aug 12 2016