digitalmars.D - Can you write better code: "alias"ing from member structs
- Russ Lewis (39/39) Dec 22 2004 I have a set of template structs, where I overload the template for many...
- Regan Heath (119/158) Dec 22 2004 Mixins. I tried the code down below but I'm getting some odd results, as...
- Ben Hinkle (21/26) Dec 22 2004 It works better when the first two struct FooA and struct FooB are repla...
- Regan Heath (88/117) Dec 22 2004 Ahh.. of course.. thanks.
- Russ Lewis (27/27) Dec 22 2004 Looks like we found a bug. I modified your code some to put out more
- Russ Lewis (6/24) Dec 22 2004 I'm pretty sure that this code shouldn't even compile, because (if I
- Thomas Kuehne (10/10) Dec 23 2004 -----BEGIN PGP SIGNED MESSAGE-----
I have a set of template structs, where I overload the template for many different numbers of parameters. To simplify code, each struct includes the previous struct. Each struct overloads opCatAssign(), taking delegates as arguments; the arguments of the delegates vary from no arguments to all of the template arguments. My problem is that I can't use 'alias' to bring in overloaded opCatAssign()s, so I have to write an increasing number of wrappers in each struct. I'm looking for a better way. Yes, 'alias' could bring in the overloaded opCatAssign()s if I used classes, but I don't want to do that; I want these to be structs, because I am going to use them by value and because I don't want to have to call constructors whenever I use them. My code looks something like this: struct Foo() { alias bool delegate() dg; dg[] opCatAssign(dg d) { ... } } struct Foo(T) { .Foo!() base; /* syntax error */ alias base.opCatAssign opCatAssign; /* what I have to do */ base.dg[] opCatAssign(base.dg d) { return base.opCatAssign(dg); } alias bool delegate(T) dg; dg[] opCatAssign(dg d) { ... } } struct Foo(T1,T2) { .Foo!(T1) base; base.base.dg[] opCatAssign(base.base.dg d) { return base.base.opCatAssign(d); } base. dg[] opCatAssign(base. dg d) { return base.base.opCatAssign(d); } alias bool delegate(T1,T2) dg; dg[] opCatAssign(dg d) { ... } } As you can see, with each parameter I add, I have more and more overloading to do. Ick. Anybody have any thoughts about a better way to do it?
Dec 22 2004
On Wed, 22 Dec 2004 11:21:08 -0700, Russ Lewis <spamhole-2001-07-16 deming-os.org> wrote:I have a set of template structs, where I overload the template for many different numbers of parameters. To simplify code, each struct includes the previous struct. Each struct overloads opCatAssign(), taking delegates as arguments; the arguments of the delegates vary from no arguments to all of the template arguments. My problem is that I can't use 'alias' to bring in overloaded opCatAssign()s, so I have to write an increasing number of wrappers in each struct. I'm looking for a better way. Yes, 'alias' could bring in the overloaded opCatAssign()s if I used classes, but I don't want to do that; I want these to be structs, because I am going to use them by value and because I don't want to have to call constructors whenever I use them. My code looks something like this: struct Foo() { alias bool delegate() dg; dg[] opCatAssign(dg d) { ... } } struct Foo(T) { .Foo!() base; /* syntax error */ alias base.opCatAssign opCatAssign; /* what I have to do */ base.dg[] opCatAssign(base.dg d) { return base.opCatAssign(dg); } alias bool delegate(T) dg; dg[] opCatAssign(dg d) { ... } } struct Foo(T1,T2) { .Foo!(T1) base; base.base.dg[] opCatAssign(base.base.dg d) { return base.base.opCatAssign(d); } base. dg[] opCatAssign(base. dg d) { return base.base.opCatAssign(d); } alias bool delegate(T1,T2) dg; dg[] opCatAssign(dg d) { ... } } As you can see, with each parameter I add, I have more and more overloading to do. Ick. Anybody have any thoughts about a better way to do it?Mixins. I tried the code down below but I'm getting some odd results, as in, this output: ----------------------------- a catAssignC catAssignB catAssignA executeA() on 3 items abar: 8855520,1 bbar: 0 cbar executeB(1) on 3 items abar: 1244968,1 bbar: 1 cbar executeC(2,3) on 3 items abar: 2,3 bbar: 3 cbar b Error: Access Violation Tool completed with exit code 1 ----------------------------- The thing that seems odd to me is that when I call 'execute' I am expecting only 1 item in each list, not 3 items, each call to catAssignC adds an item to listC, catAssignB to listB, catAssignA to listA, yet executeA finds 3 items in listA. Anyone know why? ----------------------------- import std.stdio; struct FooA() { alias bool delegate() dgA; dgA[] listA; dgA[] opCatAssign(dgA d) { writef("catAssignA\n"); listA ~= d; return listA; } void execute() { writef("executeA() on ",listA.length," items\n"); foreach(dgA d; listA) d(); } } struct FooB(T) { mixin FooA; alias FooA.opCatAssign opCatAssign; alias FooA.execute execute; alias bool delegate(T) dgB; dgB[] listB; dgB[] opCatAssign(dgB d) { writef("catAssignB\n"); listB ~= d; return listB; } void execute(T p1) { writef("executeB(",p1,") on ",listB.length," items\n"); foreach(dgB d; listB) d(p1); } } struct FooC(T1,T2) { mixin FooB!(T1); alias FooB.opCatAssign opCatAssign; alias FooB.execute execute; alias bool delegate(T1,T2) dgC; dgC[] listC; dgC[] opCatAssign(dgC d) { writef("catAssignC\n"); listC ~= d; return listC; } void execute(T1 p1, T2 p2) { writef("executeC(",p1,",",p2,") on ",listC.length," items\n"); foreach(dgC d; listC) d(p1,p2); } } class A { bool abar(int a, int b) { writef(" abar: ",a,",",b,"\n"); return true; } bool bbar(int a) { writef(" bbar: ",a,"\n"); return true; } bool cbar() { writef(" cbar\n"); return true; } } void main() { A c = new A(); FooC!(int,int) a; FooB!(int) b; writef("\na\n"); a ~= &c.abar; a ~= &c.bbar; a ~= &c.cbar; a.execute(); a.execute(1); a.execute(2,3); writef("\nb\n"); b ~= &c.bbar; b ~= &c.cbar; b.execute(); b.execute(4); } ----------------------------- Regan
Dec 22 2004
[snip]The thing that seems odd to me is that when I call 'execute' I am expecting only 1 item in each list, not 3 items, each call to catAssignC adds an item to listC, catAssignB to listB, catAssignA to listA, yet executeA finds 3 items in listA. Anyone know why?It works better when the first two struct FooA and struct FooB are replaced with template FooA and template FooB. With the struct it was mixing in a single declaration of the struct instead of all the declarations from the template since struct FooA() is treated like template FooA(){struct FooA {...}} Then when you mix that in you are doing the same thing as: struct A { struct B { int x; } int y; // note: no variable of type B. it just defines B, it does not use B void oops() { printf("%d",B.x); } } viod main(){ A a; a.y = 7; a.oops(); } [snip]
Dec 22 2004
On Wed, 22 Dec 2004 16:21:47 -0500, Ben Hinkle <bhinkle mathworks.com> wrote:[snip]Ahh.. of course.. thanks. So the mixin solution for this problem is something like: import std.stdio; template FooA() { alias bool delegate() dgA; dgA[] listA; dgA[] opCatAssign(dgA d) { writef("catAssignA\n"); listA ~= d; return listA; } void execute() { writef("executeA() on ",listA.length," items\n"); foreach(dgA d; listA) d(); } } template FooB(T) { alias bool delegate(T) dgB; dgB[] listB; dgB[] opCatAssign(dgB d) { writef("catAssignB\n"); listB ~= d; return listB; } void execute(T p1) { writef("executeB(",p1,") on ",listB.length," items\n"); foreach(dgB d; listB) d(p1); } } template FooC(T1,T2) { alias bool delegate(T1,T2) dgC; dgC[] listC; dgC[] opCatAssign(dgC d) { writef("catAssignC\n"); listC ~= d; return listC; } void execute(T1 p1, T2 p2) { writef("executeC(",p1,",",p2,") on ",listC.length," items\n"); foreach(dgC d; listC) d(p1,p2); } } struct Foo(T1,T2) { mixin FooC!(T1,T2); alias FooC!(T1,T2).opCatAssign opCatAssign; alias FooC!(T1,T2).execute execute; mixin FooB!(T1); alias FooB!(T1).opCatAssign opCatAssign; alias FooB!(T1).execute execute; mixin FooA!(); alias FooA!().opCatAssign opCatAssign; alias FooA!().execute execute; } class A { bool abar(int a, int b) { writef(" abar: ",a,",",b,"\n"); return true; } bool bbar(int a) { writef(" bbar: ",a,"\n"); return true; } bool cbar() { writef(" cbar\n"); return true; } } int main() { A c = new A(); Foo!(int,int) a; a ~= &c.abar; a ~= &c.bbar; a ~= &c.cbar; a.execute(); a.execute(1); a.execute(2,3); return 0; } Which doesn't really look any nicer than the original example. ReganThe thing that seems odd to me is that when I call 'execute' I am expecting only 1 item in each list, not 3 items, each call to catAssignC adds an item to listC, catAssignB to listB, catAssignA to listA, yet executeA finds 3 items in listA. Anyone know why?It works better when the first two struct FooA and struct FooB are replaced with template FooA and template FooB. With the struct it was mixing in a single declaration of the struct instead of all the declarations from the template since struct FooA() is treated like template FooA(){struct FooA {...}} Then when you mix that in you are doing the same thing as: struct A { struct B { int x; } int y; // note: no variable of type B. it just defines B, it does not use B void oops() { printf("%d",B.x); } } viod main(){ A a; a.y = 7; a.oops(); } [snip]
Dec 22 2004
Looks like we found a bug. I modified your code some to put out more debugging info and found that the listA and listB variables have the same location. It's not just the arrays - the address of the two variables is identical. That sounds like a compiler bug to me. However, I also think that your code is faulty, because I don't think you can mixin another struct like that. If things work the way I think they do, that would simply mixin the struct declaration, and not actually allocate any variable space. I did play around with using mixins to do variable declarations and aliasing, then wrapping them in structs, but that seemed even less readable than my original post: template Contents() { ... stuff ... } struct MyStruct() { mixin Contents!(); } template Contents(T) { mixin Contents!() base; alias base.opCatAssign opCatAssign; ... stuff ... } struct MyStruct(T) { mixin Contents!(T); } I never got it to compile, anyhow, so maybe it wouldn't have worked at all...
Dec 22 2004
I'm pretty sure that this code shouldn't even compile, because (if I understand correctly) the 'mixin Foo' line is mixing in a struct declaration, not member variables. Thus, the code should not be able to alias 'Foo.var'. Further, if you run it, it shows that the addresses of the two variables are identical, and that the size of the 'Bar!(int)' variable is 4.struct Foo() { int var; } struct Bar(T) { mixin Foo; alias Foo.var var; T var2; } import std.stdio; void main() { Bar!(int) x; x.var = 1; x.var2 = 2; writef("address of x.var=%08x x.var2=%08x\n", cast(int)&x.var, cast(int)&x.var2); writef("size of x = %d\n", x.sizeof); }
Dec 22 2004
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Added to DStress as http://svn.kuehne.cn/dstress/nocompile/mixin_04.d Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFByy5D3w+/yD4P9tIRAp8nAKCbyZ/vnA7YRIXYeBPKA5l4h/KkHgCcCxW2 28dwoKFdwMj9UwB7UYksfVw= =hpYk -----END PGP SIGNATURE-----
Dec 23 2004