digitalmars.D.learn - How to group similar member functions from different classes?
- cy (36/36) Jun 18 2016 When I define functions like:
- cy (37/39) Jun 18 2016 The only thing I've been able to figure is a horrible hack, where
- kinke (12/14) Jun 18 2016 No such thing in D. But you can always be creative and use an
- Marc =?UTF-8?B?U2Now7x0eg==?= (21/21) Jun 20 2016 Untested:
- cy (24/25) Jul 15 2016 Seems to only work if A and B are both defined in the same file
- Marc =?UTF-8?B?U2Now7x0eg==?= (11/36) Jul 18 2016 It works if you add forward declarations for the classes:
When I define functions like: class A { abstract void format(...) {...} } class B : A { void format(...) {...} } class C : A { void format(...) {...} } and so on, often these different member functions all share a lot in common. Maybe they are the only ones that require formatting modules, that do I/O, that do string manipulation, that sort of thing. But if I made a second function, say for instance clone() or replaceWithDucks(), it too might import a lot of modules, and perform a lot of logic. And there may be many, many different types of object here. In C++ I could forward declare the member functions, then put all "::format(...)" member functions together in their own source file, making everything pretty neat and tidy. How do I do that in D? As near as I can tell, you can only define member functions inside the class definition itself, and you can't add to that definition piece-wise like // file 1 class A ... { void format(...) { ... } } ... // file 2 class A ... { void doathing() { ... } } ... So how would you do it? Defining A.foo, B.foo, etc in one place, and A.bar, B.bar, etc in another?
Jun 18 2016
On Saturday, 18 June 2016 at 07:03:25 UTC, cy wrote:So how would you do it? Defining A.foo, B.foo, etc in one place, and A.bar, B.bar, etc in another?The only thing I've been able to figure is a horrible hack, where your member functions are something like // off in define_foos.d template foo_for(T) { static if(is(T == A)) { enum foo_for = q{ int foo () { return bar+42; } }; } else static if(is(T == B)) { enum foo_for = q{ int foo () { return bar+23; } }; } } // in classes.d import define_foos: foo_for; struct A { int bar; mixin(foo_for!A); } struct B { int bar; mixin(foo_for!B); } // etc void main() { import std.stdio; A a = A(0); B b = B(1); writeln(b.foo()); writeln(a.foo()); }
Jun 18 2016
On Saturday, 18 June 2016 at 07:03:25 UTC, cy wrote:So how would you do it? Defining A.foo, B.foo, etc in one place, and A.bar, B.bar, etc in another?No such thing in D. But you can always be creative and use an overloaded helper function containing the actual implementation if you want to group the code by functionality and not by type: class A { int foo() { return doFoo(this); } class B : A { int foo() { return doFoo(this); } ... void doFoo(A a) { ... } void doFoo(B b) { ... } If you need full access to the members, the helpers would need to be in the same module, otherwise you can put them into a separate helper.
Jun 18 2016
Untested: // foo.d import a, b; mixin template Foos { static if(is(typeof(this) == A)) void foo() { /* implementation for A */ } static if(is(typeof(this) == B)) void foo() { /* implementation for B */ } } // a.d import foo; class A { mixin Foos; } // b.d import foo; class B { mixin Foos; } You must not have static constructors in any of these modules because you'd likely get problems with circular initialization.
Jun 20 2016
On Monday, 20 June 2016 at 16:39:54 UTC, Marc Schütz wrote:Untested:Seems to only work if A and B are both defined in the same file as Foos (defeating the purpose). Putting A and B in a.d and b.d respectively gives me these errors: a.d(2): Error: undefined identifier 'Foos' a.d(2): Error: mixin a.A.Foos!() is not defined b.d(2): Error: undefined identifier 'Foos' b.d(2): Error: mixin b.B.Foos!() is not defined I also tried switching it around, like // b.d import foos Foos; class B { mixin Foos; } but that of course gives the error: foos.d(4): Error: undefined identifier 'A' b.d(3): Error: mixin b.B.Foos!() error instantiating since you can't do a static if(typeof(this) == A) without importing A from a somehow. (you can do else static if(typeof(this) == B) without importing B though, since it does the branch for A first) I think a mixin here is just required, because you can't use an identifier before it's defined, even at compile time. Honestly, I have yet to find a use for mixin templates.
Jul 15 2016
On Friday, 15 July 2016 at 17:25:23 UTC, cy wrote:On Monday, 20 June 2016 at 16:39:54 UTC, Marc Schütz wrote:It works if you add forward declarations for the classes: import a, b; class A; class B; mixin template Foos() { static if(is(typeof(this) == A)) void foo() { /* implementation for A */ } static if(is(typeof(this) == B)) void foo() { /* implementation for B */ } }Untested:Seems to only work if A and B are both defined in the same file as Foos (defeating the purpose). Putting A and B in a.d and b.d respectively gives me these errors: a.d(2): Error: undefined identifier 'Foos' a.d(2): Error: mixin a.A.Foos!() is not defined b.d(2): Error: undefined identifier 'Foos' b.d(2): Error: mixin b.B.Foos!() is not defined I also tried switching it around, like // b.d import foos Foos; class B { mixin Foos; } but that of course gives the error: foos.d(4): Error: undefined identifier 'A' b.d(3): Error: mixin b.B.Foos!() error instantiating since you can't do a static if(typeof(this) == A) without importing A from a somehow. (you can do else static if(typeof(this) == B) without importing B though, since it does the branch for A first) I think a mixin here is just required, because you can't use an identifier before it's defined, even at compile time. Honestly, I have yet to find a use for mixin templates.
Jul 18 2016