digitalmars.D - A lightweight module for class extensions in D
- Gregor Richards (14/14) Dec 05 2008 I ran into a situation where I needed (essentially) the visitor pattern,...
- Robert Fraser (6/28) Dec 05 2008 Pretty cool stuff, but I don't see how this is at all better than the
- Gregor Richards (8/47) Dec 05 2008 The visitor pattern requires annotating every class in the hierarchy.
- Robert Fraser (17/68) Dec 05 2008 I agree that this has other uses, so mad props for making it.
- Nick Sabalausky (9/79) Dec 06 2008 I'd rather have a type that all other types derive from. Sort of like
- Robert Fraser (8/26) Dec 06 2008 That's one way to think about it. I was thinking that in a C++ header
- Christopher Wright (5/9) Dec 07 2008 This would be convenient. I think, if Walter were for this idea, it'd be...
- Nick Sabalausky (275/286) Dec 07 2008 I came across a need for it in a command-line parser I'm writing, but en...
- Christopher Wright (19/20) Dec 05 2008 I usually use this pattern but make it more explicit, using interfaces
- Nick Sabalausky (5/29) Dec 06 2008 Congrats for getting an extension-like feature into D through a simple l...
- Janderson (4/26) Dec 06 2008 What about using a delegate, function pointer or a functor for your
- Christian Kamm (7/7) Dec 07 2008 I had done something similar, albeit using D2 and traits, in
- Gregor Richards (7/16) Dec 07 2008 Yes.
I ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition). Of course, it's not possible to do this particularly cleanly, but I made a system that works (albeit using gross string mixins). Essentially, if you have a class A, class B : A, class C : B, you could do something like this: mixin(extensions("A", "void", "doFoo", "", "")); mixin(extend("A", "doFoo")); void A_doFoo(A pthis) { /* method for A */ } mixin(extend("B", "doFoo")); void B_doFoo(B pthis) { /* method for B */ } Then if you call doFoo(new A()) the call will become A_doFoo(new A()), if you call doFoo(new B()) the call will become B_doFoo(new B()), if you call doFoo(new C()) the call will become B_doFoo(new C()). If anybody has some improvements, that'd be cool. Maybe you can get rid of the dependence on string mixins ... but I don't think templates quite cut it. - Gregor Richards
Dec 05 2008
Gregor Richards wrote:I ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition). Of course, it's not possible to do this particularly cleanly, but I made a system that works (albeit using gross string mixins). Essentially, if you have a class A, class B : A, class C : B, you could do something like this: mixin(extensions("A", "void", "doFoo", "", "")); mixin(extend("A", "doFoo")); void A_doFoo(A pthis) { /* method for A */ } mixin(extend("B", "doFoo")); void B_doFoo(B pthis) { /* method for B */ } Then if you call doFoo(new A()) the call will become A_doFoo(new A()), if you call doFoo(new B()) the call will become B_doFoo(new B()), if you call doFoo(new C()) the call will become B_doFoo(new C()). If anybody has some improvements, that'd be cool. Maybe you can get rid of the dependence on string mixins ... but I don't think templates quite cut it. - Gregor RichardsPretty cool stuff, but I don't see how this is at all better than the visitor pattern. It is not checked at compile-time (so if you forget to implement one part of the hierarchy, you won't find that out until runtime) and it's likely less efficient, especially for large enough hierarchies (i.e. syntax trees). Where's the happy?
Dec 05 2008
Robert Fraser wrote:Gregor Richards wrote:The visitor pattern requires annotating every class in the hierarchy. That's what annoys me about it. I'd like my AST nodes to just be AST nodes. Yes, calling a function is less efficient. It can probably be improved, I'm just not sure how yet :P Plus, of course, although the visitor pattern is the example I gave, this is a more general mechanism. - Gregor RichardsI ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition). Of course, it's not possible to do this particularly cleanly, but I made a system that works (albeit using gross string mixins). Essentially, if you have a class A, class B : A, class C : B, you could do something like this: mixin(extensions("A", "void", "doFoo", "", "")); mixin(extend("A", "doFoo")); void A_doFoo(A pthis) { /* method for A */ } mixin(extend("B", "doFoo")); void B_doFoo(B pthis) { /* method for B */ } Then if you call doFoo(new A()) the call will become A_doFoo(new A()), if you call doFoo(new B()) the call will become B_doFoo(new B()), if you call doFoo(new C()) the call will become B_doFoo(new C()). If anybody has some improvements, that'd be cool. Maybe you can get rid of the dependence on string mixins ... but I don't think templates quite cut it. - Gregor RichardsPretty cool stuff, but I don't see how this is at all better than the visitor pattern. It is not checked at compile-time (so if you forget to implement one part of the hierarchy, you won't find that out until runtime) and it's likely less efficient, especially for large enough hierarchies (i.e. syntax trees). Where's the happy?
Dec 05 2008
Gregor Richards wrote:Robert Fraser wrote:I agree that this has other uses, so mad props for making it. This way, each node needs only to be annotated once for visitors, no matter what they return (with variadic arguments used for parameters, too). Unrelated (but the main reason I use visitors), I wish D could allow could declaring a virtual function in the class definition but implement it elsewhere (a la C++). So... module1.d: ---------- module module1; class A { int foo(int x); } module 2.d: ----------- module module2; import module1; int A.foo(int x) { return x; }Gregor Richards wrote:The visitor pattern requires annotating every class in the hierarchy. That's what annoys me about it. I'd like my AST nodes to just be AST nodes. Yes, calling a function is less efficient. It can probably be improved, I'm just not sure how yet :P Plus, of course, although the visitor pattern is the example I gave, this is a more general mechanism. - Gregor RichardsI ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition). Of course, it's not possible to do this particularly cleanly, but I made a system that works (albeit using gross string mixins). Essentially, if you have a class A, class B : A, class C : B, you could do something like this: mixin(extensions("A", "void", "doFoo", "", "")); mixin(extend("A", "doFoo")); void A_doFoo(A pthis) { /* method for A */ } mixin(extend("B", "doFoo")); void B_doFoo(B pthis) { /* method for B */ } Then if you call doFoo(new A()) the call will become A_doFoo(new A()), if you call doFoo(new B()) the call will become B_doFoo(new B()), if you call doFoo(new C()) the call will become B_doFoo(new C()). If anybody has some improvements, that'd be cool. Maybe you can get rid of the dependence on string mixins ... but I don't think templates quite cut it. - Gregor RichardsPretty cool stuff, but I don't see how this is at all better than the visitor pattern. It is not checked at compile-time (so if you forget to implement one part of the hierarchy, you won't find that out until runtime) and it's likely less efficient, especially for large enough hierarchies (i.e. syntax trees). Where's the happy?
Dec 05 2008
"Robert Fraser" <fraserofthenight gmail.com> wrote in message news:ghcj02$2kpi$1 digitalmars.com...Gregor Richards wrote:I'd rather have a type that all other types derive from. Sort of like "Object" (or is it "object"?), but serves as the base type for all types, not just classes. Not sure if this would be possible though (having vtables for every int and char in the program doesn't sound like a good idea ;) ).Robert Fraser wrote:I agree that this has other uses, so mad props for making it. This way, each node needs only to be annotated once for visitors, no matter what they return (with variadic arguments used for parameters, too).Gregor Richards wrote:The visitor pattern requires annotating every class in the hierarchy. That's what annoys me about it. I'd like my AST nodes to just be AST nodes. Yes, calling a function is less efficient. It can probably be improved, I'm just not sure how yet :P Plus, of course, although the visitor pattern is the example I gave, this is a more general mechanism. - Gregor RichardsI ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition). Of course, it's not possible to do this particularly cleanly, but I made a system that works (albeit using gross string mixins). Essentially, if you have a class A, class B : A, class C : B, you could do something like this: mixin(extensions("A", "void", "doFoo", "", "")); mixin(extend("A", "doFoo")); void A_doFoo(A pthis) { /* method for A */ } mixin(extend("B", "doFoo")); void B_doFoo(B pthis) { /* method for B */ } Then if you call doFoo(new A()) the call will become A_doFoo(new A()), if you call doFoo(new B()) the call will become B_doFoo(new B()), if you call doFoo(new C()) the call will become B_doFoo(new C()). If anybody has some improvements, that'd be cool. Maybe you can get rid of the dependence on string mixins ... but I don't think templates quite cut it. - Gregor RichardsPretty cool stuff, but I don't see how this is at all better than the visitor pattern. It is not checked at compile-time (so if you forget to implement one part of the hierarchy, you won't find that out until runtime) and it's likely less efficient, especially for large enough hierarchies (i.e. syntax trees). Where's the happy?Unrelated (but the main reason I use visitors), I wish D could allow could declaring a virtual function in the class definition but implement it elsewhere (a la C++). So... module1.d: ---------- module module1; class A { int foo(int x); } module 2.d: ----------- module module2; import module1; int A.foo(int x) { return x; }the ability to say "Compiling should fail if I've forgotten to define bodies for any of the following functions"?
Dec 06 2008
Nick Sabalausky wrote:That's one way to think about it. I was thinking that in a C++ header file you o this: class A { public: int foo(int x); } And in another file you do this: #include "A.h" int A::foo(int x) { } If foo is not implemented, the failure is at link time.Unrelated (but the main reason I use visitors), I wish D could allow could declaring a virtual function in the class definition but implement it elsewhere (a la C++). So... module1.d: ---------- module module1; class A { int foo(int x); } module 2.d: ----------- module module2; import module1; int A.foo(int x) { return x; }the ability to say "Compiling should fail if I've forgotten to define bodies for any of the following functions"?
Dec 06 2008
Nick Sabalausky wrote:I'd rather have a type that all other types derive from. Sort of like "Object" (or is it "object"?), but serves as the base type for all types, not just classes. Not sure if this would be possible though (having vtables for every int and char in the program doesn't sound like a good idea ;) ).This would be convenient. I think, if Walter were for this idea, it'd be implemented via automatic boxing. That gives you the efficiency of using That said, I seriously doubt this will be a priority for Walter, ever.
Dec 07 2008
"Christopher Wright" <dhasenan gmail.com> wrote in message news:ghgikj$2ckq$1 digitalmars.com...Nick Sabalausky wrote:I came across a need for it in a command-line parser I'm writing, but ended up having to define a boxing class myself ("RefBox!(T)", which can then be cast to "Object", although I should probably create a special base class for all the "RefBox!(T)"'s) and use a string mixin to clean up usage. I would much rather use a standardized boxer though. A "dynamic/variant" type would probably work too, but I don't like doing any runtime type variance other than polymorphism and boxing. If anyone's interested, my code is attached. I think the only part of my util module this uses is "stformat()" which is nothing more than the following helper code for Tango's Layout!(T): Layout!(char) stformat; static this() { stformat = new Layout!(char)(); } begin 666 cmdlineparser.d M+R\ 4V5M:51W:7-T($QI8G)A<GD-"B\O(%=R:71T96X :6X =&AE($0 <')O M;W)E+D%R<F%Y.PT*:6UP;W)T('1A;F=O+FEO+E-T9&]U=#L-"FEM<&]R="!T M;6%I;BAC:&%R6UU;72!A<F=S*0T*>PT*"6)O;VP :&5L<#L-" EB;V]L(&1E M+FEN:70 *&EE+"!F86QS92D-" EC:&%R6UT ;7E3='([(" O+R!$969A=6QT M('9A;'5E(#T]("AC:&%R6UTI+FEN:70 *&EE+" B(BD-" T*"6%U=&\ 8VUD M(#T ;F5W($-M9$QI;F5087)S97(H*3L-" EM:7AI;BAD969I;F5!<F<A*&-M M9"P :&5L<"P (" (" (D1I<W!L87ES(&$ :&5L<"!S=6UM87)Y(&%N9"!E M(")$:7-P;&%Y<R!A(&1E=&%I;&5D(&AE;' ;65S<V%G92!A;F0 97AI=',B M("DI.PT*"6UI>&EN*&1E9FEN94%R9R$H8VUD+"!M>4EN="P (")!;B!I;G1E M9V5R(BDI.PT*"6UI>&EN*&1E9FEN94%R9R$H8VUD+"!M>4)O;VPL(")!(&9L M:6YG(BDI.PT*"0T*"6EF*"%C;60N<&%R<V4H87)G<RD ?'P :&5L<"D-" E[ M;6%T*")[?2(L(&-M9"YG971$971A:6QE9%5S86=E*"DI.PT*"0ER971U<FX[ M86UP;&4 0V]M;6%N9"!,:6YE<SH-"CX ;7E!<' N97AE("]M>4EN=#HU("]M M>4)O;VP +VUY4W1R.F)L86 -"CX ;7E!<' N97AE("UM>4EN=#TU("UM>4)O M;VPZ=')U92 M;7E3='(Z8FQA: T*/B!M>4%P<"YE>&4 +2UM>4EN=#TU("]M M>4)O;VPK("(M;7E3='(Z8FQA:"(-"FUY26YT.B -0T*;7E";V]L.B!T<G5E M;W)L9"(-"FUY26YT.B , T*;7E";V]L.B!F86QS90T*;7E3='(Z("!(96QL M<B G+2TG*0T*(" O:&5L<" (" (" (" (" ($1I<W!L87ES(&$ :&5L M<"!S=6UM87)Y(&%N9"!E>&ET<PT*(" O9&5T86EL:&5L<" (" (" ($1I M<W!L87ES(&$ 9&5T86EL960 :&5L<"!M97-S86=E(&%N9"!E>&ET<PT*(" O M;7E);G0Z/&EN=#X M86QI87, 8VUD3&EN95!A<G-E<BP 86QI87, =F%R+"!C:&%R6UT 9&5S8RD- M"GL-" EC;VYS="!C:&%R6UT 9&5F:6YE07)G(#T-" D)(F%U=&\ 7V-M9&%R M9U]R969B;WA?(GYV87(N<W1R:6YG;V9^(B ](&YE=R!2969";W A*")^='EP M"2)A=71O(%]C;61A<F=?(GYV87(N<W1R:6YG;V9^(B ](&YE=R!!<F<H7V-M M9&%R9U]R969B;WA?(GYV87(N<W1R:6YG;V9^8"P (F!^=F%R+G-T<FEN9V]F M?F B+" B8'YD97-C?F B*3M ? T*"0EC;61,:6YE4&%R<V5R+G-T<FEN9V]F M?B(N861D07)G*%]C;61A<F=?(GYV87(N<W1R:6YG;V9^(BD[(CL-" DO+W!R M+U1/1$\Z($%D9"!F;&]A="P 9&]U8FQE+"!B>71E+"!S:&]R="P ;&]N9RP M('5S969U;"!F;W( =F%R:6%B;&5S(&]F('!R:6UI=&EV92!T>7!E<RX-"F-L M87-S(%)E9D)O>"A4*0T*>PT*"7!R:79A=&4 5"H =F%L.PT*"7!R:79A=&4 M(#T )F]P=&EO;F%L5F%L4W)C.PT*"7T-" D-" ET:&ES*%0J('9A;"D-" E[ M"0ER971U<FX *G9A;#L- M"0ER971U<FX *G1H:7,N=F%L(#T]('9A;#L- M*2!D=7 H*0T*"7L-" D)875T;R!N97=";W /2!N97< 4F5F0F]X(2A4*2 I M"6-H87);72!U;FMN;W=N(#T M86UE(#T ;RYC;&%S<VEN9F\N;F%M93L-" D-" EA=71O('-T87)T(#T ;&]C M871E4&%T=&5R;E!R:6]R*'1Y<&5.86UE+"!H96%D*3L-" EI9BAS=&%R=" ] M("L](&AE860N;&5N9W1H.PT*"0D-" EA=71O(&5N9" ](&QO8V%T92AT>7!E M92 B4F5F0F]X(2 N+BXI(B!I<R!N;W0 8W5R<F5N=&QY('-U<'!O<G1E9 T* M"6EF*'1A;F=O+G1E>'0N571I;"YC;VYT86EN<RAT>7!E3F%M95MS=&%R="XN M<EM=("!N86UE.PT*"6-H87);72 86QT3F%M93L-" EC:&%R6UT (&1E<V,[ M=6ER960 (" /2!F86QS93L-" EB;V]L(&%R<F%Y375L=&EP;&4 /2!F86QS M93L-" EB;V]L(&%R<F%Y56YI<75E(" /2!F86QS93L-" D-" EP<FEV871E M($]B:F5C="!V86QU93L-" EP<FEV871E($]B:F5C="!D969A=6QT5F%L=64[ M9"!G96Y$969A=6QT5F%L=64H*0T*"7L-" D)875T;R!V86Q!<TEN=" /2!C M87-T*%)E9D)O>"$H:6YT(" *2EV86QU93L-" D)875T;R!V86Q!<T)O;VP M/2!C87-T*%)E9D)O>"$H8F]O;" *2EV86QU93L-" D)875T;R!V86Q!<U-T M<B /2!C87-T*%)E9D)O>"$H8VAA<EM=*2EV86QU93L-" T*"0EI9B (" M*'9A;$%S26YT*2 9&5F875L=%9A;'5E(#T M"65L<V4 :68H=F%L07-";V]L*2!D969A=6QT5F%L=64 /2!V86Q!<T)O;VPN M>PT*"0DO+U1/1$\Z(&%R<F%Y375L=&EP;&4 86YD(&%R<F%Y56YI<75E(&-A M=" ("DI=F%L=64 )B8-" D)(" ("%C87-T*%)E9D)O>"$H8F]O;" *2EV M86QU92 F) T*"0D (" (6-A<W0H4F5F0F]X(2AC:&%R6UTI*79A;'5E("D- M" D)>PT*"0D)=&AR;W< ;F5W($5X8V5P=&EO;B B4&%R86T =&\ 07)G(&-O M;G1R=6-T;W( ;7ES="!B92!2969";W A*%0I+"!W:&5R92!4(&ES(&EN="P M8F]O;"!O<B!C:&%R6UTB*3L-" D)?0T*"0D-" D)=F]I9"!E;G-U<F5686QI M+FES5F%L:61!<F=.86UE*&YA;64I*0T*"0D)"71H<F]W(&YE=R!%>&-E<'1I M;VXH<W1F;W)M870H8%1R:65D('1O(&1E9FEN92!A;B!I;G9A;&ED(&%R9R!N M86UE.B B>WTB+B!!<F< ;F%M97, ;75S="!B92 B6V$M>D$M6C M.5\_72LB M96YS=7)E5F%L:61.86UE*&%L=$YA;64I.PT*"0D-" D):68H;F%M92 ]/2 B M(BD-" D)"71H<F]W(&YE=R!%>&-E<'1I;VXH8%1R:65D('1O(&1E9FEN92!A M87);75T 87)G3&]O:W5P.PT*"0T*"7!R:79A=&4 96YU;2!0<F5F:7 -" E[ M=6YD+"!%<G)O< T*"7T-" D-" ES=&%T:6, 8F]O;"!I<U9A;&ED07)G3F%M M<G5E.PT*"7T-" D-" EP<FEV871E('9O:60 96YS=7)E5F%L:60H*0T*"7L- M5F%L:60H*3L-" D)?0T*"7T-" D-" EP<FEV871E('9O:60 <&]P=6QA=&5, M"0EA9&14;T%R9TQO;VMU<"AA<F<N;F%M92P 87)G*3L-" D)"0T*"0D):68H M"7L-" D)"6%R9RYG96Y$969A=6QT5F%L=64H*3L-" D)?0T*"7T-" T*"7!U M8FQI8R!V;VED(&%D9$%R9RA!<F< 87)G*0T*"7L-" D)87)G<R!^/2!A<F<[ M*0T*"0D)=&AR;W< ;F5W($5X8V5P=&EO;BAS=&9O<FUA="A 07)G=6UE;G0 M;F%M92 B>WTB(&1E9FEN960 ;6]R92!T:&%N(&]N8V4N8"P ;F%M92DI.PT* M92!V;VED('-P;&ET07)G*&-H87);72!F=6QL07)G+"!O=70 4')E9FEX('!R M969I>"P ;W5T(&-H87);72!N86UE+"!O=70 8VAA<EM=('-U9F9I>"D-" E[ M"6EF*&9U;&Q!<F<N;&5N9W1H(#X ,B F)B!F=6QL07)G6S N+C)=(#T]("(M M"0D)"7!R969I>" ](%!R969I>"Y3:6YG;&5$87-H.PT*"0D)96QS92!I9BAF M=6QL07)G6S!=(#T]("<O)RD-" D)"0EP<F5F:7 /2!0<F5F:7 N4VQA<V [ M"0DO+R!'970 <W5F9FEX(&%N9"!A<F< ;F%M90T*"0EA=71O('-U9F9I>$EN M9&5X(#T ;6EN*"!T86YG;RYC;W)E+D%R<F%Y+F9I;F0H87)G3F]0<F5F:7 L M969I>"P )RLG*2P-" D)"0D)"0D)=&%N9V\N8V]R92Y!<G)A>2YF:6YD*&%R M+B1=(#H M94%R9RAC:&%R6UT 8VUD07)G+"!0<F5F:7 <')E9FEX+"!C:&%R6UT 8VUD M=" ](%!A<G-E07)G4F5S=6QT+D5R<F]R.PT*"0D-" D)=F]I9"!(86YD;&5- M94%R9U)E<W5L="Y%<G)O<CL-" D)?0T*"0D-" D):68H8VUD3F%M92!I;B!A M9$YA;65=.PT*"0D)875T;R!V86Q!<TEN=$)O>" /2!C87-T*%)E9D)O>"$H M(&-A<W0H4F5F0F]X(2AB;V]L(" I*6%R9T1E9BYV86QU93L-" D)"6%U=&\ M=F%L07-3=')";W (#T 8V%S="A2969";W A*&-H87);72DI87)G1&5F+G9A M.G1R=64B. T*"0D)"0EV86Q!<T)O;VQ";W /2!T<G5E.PT*"0D)"0EB<F5A M:SL-" D)"0EC87-E("(M(CH-" D)"0EC87-E("(Z9F%L<V4B. T*"0D)"0EV M=#H-" D)"0D)2&%N9&QE36%L9F]R;65D07)G=6UE;G0H*3L-" D)"0D)8G)E M"7L-" D)"0EI9BAS=69F:7 N;&5N9W1H(#X ,2 F)B!S=69F:7A;,%T /3T M)SHG*0T*"0D)"0EV86Q!<U-T<D)O>" ]('1R:6TH<W5F9FEX6S$N+B1=*3L- M86P 17)R;W(Z($9A:6QE9"!T;R!P<F]C97-S(&%N($%R9RYV86QU92!T>7!E M('1H870 :&%S;B=T(&)E96X <V5T(&%S('5N<W5P<&]R=&5D+B(I.PT*"0E] M:71C:#H M="Y.;W1&;W5N9#L-" D)?0T*"0D-" D)<F5T=7)N(')E=#L- M;"!P87)S92AC:&%R6UU;72!A<F=S*0T*"7L-" D)8F]O;"!E<G)O<CUF86QS M(&%R9U-T<CL 87)G<ULQ+BXD72D-" D)>PT*"0D)8VAA<EM=('-U9F9I>#L- M" D)"6-H87);72!A<F=.86UE.PT*"0D)4')E9FEX('!R969I>#L-" D)"0T* M"0D)<W!L:71!<F<H87)G4W1R+"!P<F5F:7 L(&%R9TYA;64L('-U9F9I>"D[ M4W1D;W5T+F9O<FUA=&QN*&!5;F5X<&5C=&5D('9A;'5E.B B>WTB8"P 87)G M(F%R9TYA;64B+" B<W5F9FEX("(I*3L-" D)"0T*"0D)875T;R!R97-U;'0 M/2!P87)S94%R9RAA<F=3='(L('!R969I>"P 87)G3F%M92P <W5F9FEX*3L- M07)G4F5S=6QT+D5R<F]R. T*"0D)8V%S92!087)S94%R9U)E<W5L="Y.;W1& M;W5N9#H- M9F]R;6%T*")5;F5X<&5C=&5D(%!A<G-E07)G4F5S=6QT.B H>WTI(BP <F5S M"0T*"2\O5$]$3SH 36%K92!F=6YC=&EO;B!T;R!G970 =&AE(&UA>&EM=6T M;&5N9W1H(&]F('1H92!A<F< ;F%M97,-" T*"7!R:79A=&4 8VAA<EM=('-W M:71C:%1Y<&5S37-G(#T- M4V5T(', =&\ 9F%L<V4Z("]S+2 O<SIF86QS90T*(" ($1E9F%U;'0 =F%L M(&-H87);73H-"B ("!3970 <R!T;R B=&5X="(Z("]S.G1E>'0-"B ("!$ M969A=6QT('9A;'5E.B B(B H=6YL97-S(&]T:&5R=VES92!N;W1E9"D-" D) M"0EC:&%R6UT <F5T.PT*"0EC:&%R6UT :6YD96YT(#T M"7)E="!^/2 B4W=I=&-H97,Z("AP<F5F:7AE<R!C86X 8F4 )R\G+" G+2< M"0D)875T;R!V86Q!<TEN=$)O>" /2!C87-T*%)E9D)O>"$H:6YT(" *2EA M<F<N9&5F875L=%9A;'5E.PT*"0D)875T;R!V86Q!<T)O;VQ";W /2!C87-T M*%)E9D)O>"$H8F]O;" *2EA<F<N9&5F875L=%9A;'5E.PT*"0D)875T;R!V M86Q!<U-T<D)O>" /2!C87-T*%)E9D)O>"$H8VAA<EM=*2EA<F<N9&5F875L M26YT0F]X*0T*"0D)"61E9F%U;'1686P /2!S=&9O<FUA=" B>WTB+"!V86Q! M<TEN=$)O>" I*3L-" D)"65L<V4 :68H=F%L07-";V]L0F]X*0T*"0D)"61E M9F%U;'1686P /2!V86Q!<T)O;VQ";W H*2 _(")T<G5E(B Z("(B.PT*"0D) M96QS92!I9BAV86Q!<U-T<D)O>"D-" D)"0ED969A=6QT5F%L(#T =F%L07-3 M=')";W H*2 ]/2 B(B _("(B(#H <W1F;W)M870H8")[?2) +"!V86Q!<U-T M<D)O>" I*3L-" D)"0T*"0D)8VAA<EM=(&1E9F%U;'1686Q3='( /2!D969A M=6QT5F%L(#T M('M]*2(L(&1E9F%U;'1686PI.PT*"0D)"0T*"0D)8VAA<EM=(&%R9U-U9F9I M>" ]('9A;$%S0F]O;$)O>" _("(B(#H (CH\(GYG9712969";WA4>7!E3F%M M?F%R9RYN86UE?F%R9U-U9F9I>#L-" D)"6EF*&%R9RYA;'1.86UE("$]("(B M*0T*"0D)"6%R9TYA;64 ?CT (BP +R)^87)G+F%L=$YA;65^87)G4W5F9FEX M(GM]>RPM(GYN86UE0V]L=6UN5VED=&A3=')^(GU[?7M]7&XB+ T*"0D)(" M(" (" (" (" (&EN9&5N="P 87)G3F%M97XB("(L(&%R9RYD97-C+"!D M969A=6QT5F%L4W1R*3L-" D)?0T*"0ER971U<FX <F5T.PT*"7T-" T*"6-H M"6-H87);72!I;F1E;G0 /2 B(" B.PT*"0D-" D)<F5T('X](")3=VET8VAE M<SH *'!R969I>&5S(&-A;B!B92 G+R<L("<M)R!O<B G+2TG*5QN(CL-" D) M92 ]("(O(GYA<F<N;F%M93L-" D)"6EF*&%R9RYA;'1.86UE("$]("(B*0T* M('9A;$%S26YT0F]X(" ](&-A<W0H4F5F0F]X(2AI;G0 (" I*6%R9RYD969A M0F]X(" ](&-A<W0H4F5F0F]X(2AC:&%R6UTI*6%R9RYD969A=6QT5F%L=64[ M;" ]('-T9F]R;6%T*")[?2(L('9A;$%S0F]O;$)O>" I*3L-" D)"65L<V4 M"0D)<F5T('X]('-T9F]R;6%T*")[?2 H>WTI+"!D969A=6QT.B![?5QN(BP- M" D)"2 (" (" (" (" ("!A<F=.86UE+"!G9712969";WA4>7!E3F%M M92AA<F<N=F%L=64I+"!D969A=6QT5F%L*3L-" D)"7)E="!^/2!S=&9O<FUA M=" B>WU<;B(L(&%R9RYD97-C*3L-" D)?0T*"0ER970 ?CT (EQN(CL-" D) M<F5T('X]('-W:71C:%1Y<&5S37-G.PT*"0ER971U<FX <F5T.PT*"7T-"GT- !" `` ` endI'd rather have a type that all other types derive from. Sort of like "Object" (or is it "object"?), but serves as the base type for all types, not just classes. Not sure if this would be possible though (having vtables for every int and char in the program doesn't sound like a good idea ;) ).This would be convenient. I think, if Walter were for this idea, it'd be implemented via automatic boxing. That gives you the efficiency of using That said, I seriously doubt this will be a priority for Walter, ever.
Dec 07 2008
Gregor Richards wrote:I ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition).I usually use this pattern but make it more explicit, using interfaces and direct casting in client code. I'm not sure I want to use this, given that it does use string mixins. You could define the "extension" method more like: char[] textension(char[] funcname, TTarget, TReturn, TArgs...)() { return extension (TTarget.stringof, TReturn.stringof, funcname, GetTypedArgString!(TArgs), GetUntypedArgString!(TArgs)); } And extend: template extend(char[] funcname, alias func) { static this () { mixin (`__ext_` ~ funcname ~ `[ParameterTupleOf!(func)[0].classinfo] = cast(void*) &func;`); } }
Dec 05 2008
"Gregor Richards" <Richards codu.org> wrote in message news:ghbld5$23j7$1 digitalmars.com...I ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition). Of course, it's not possible to do this particularly cleanly, but I made a system that works (albeit using gross string mixins). Essentially, if you have a class A, class B : A, class C : B, you could do something like this: mixin(extensions("A", "void", "doFoo", "", "")); mixin(extend("A", "doFoo")); void A_doFoo(A pthis) { /* method for A */ } mixin(extend("B", "doFoo")); void B_doFoo(B pthis) { /* method for B */ } Then if you call doFoo(new A()) the call will become A_doFoo(new A()), if you call doFoo(new B()) the call will become B_doFoo(new B()), if you call doFoo(new C()) the call will become B_doFoo(new C()). If anybody has some improvements, that'd be cool. Maybe you can get rid of the dependence on string mixins ... but I don't think templates quite cut it. - Gregor RichardsCongrats for getting an extension-like feature into D through a simple lib. But I hope nobody (*cough* Walter) mistakes this as a sufficient substitute for real extension methods (*hint* *hint*) ;)
Dec 06 2008
Gregor Richards wrote:I ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition). Of course, it's not possible to do this particularly cleanly, but I made a system that works (albeit using gross string mixins). Essentially, if you have a class A, class B : A, class C : B, you could do something like this: mixin(extensions("A", "void", "doFoo", "", "")); mixin(extend("A", "doFoo")); void A_doFoo(A pthis) { /* method for A */ } mixin(extend("B", "doFoo")); void B_doFoo(B pthis) { /* method for B */ } Then if you call doFoo(new A()) the call will become A_doFoo(new A()), if you call doFoo(new B()) the call will become B_doFoo(new B()), if you call doFoo(new C()) the call will become B_doFoo(new C()). If anybody has some improvements, that'd be cool. Maybe you can get rid of the dependence on string mixins ... but I don't think templates quite cut it. - Gregor RichardsWhat about using a delegate, function pointer or a functor for your visitor pattern? -Joel
Dec 06 2008
I had done something similar, albeit using D2 and traits, in http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=56018 It's good to see it's possible in D1! The main advantage of __traits seems to be that you can avoid building a lookup table and thereby simplify the user interface. On the other hand, your approach will probably work even when the extension methods are defined in different modules, as long as the one with the extensions mixin is imported?
Dec 07 2008
Christian Kamm wrote:I had done something similar, albeit using D2 and traits, in http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=56018 It's good to see it's possible in D1! The main advantage of __traits seems to be that you can avoid building a lookup table and thereby simplify the user interface. On the other hand, your approach will probably work even when the extension methods are defined in different modules, as long as the one with the extensions mixin is imported?Yes. The best solution IMHO would be to be able to declare things to be in the vtable that aren't functions (but are, for example, a pointer to some area of globally-accessible-and-writable memory). Then you could effectively have a sub-vtable. But alas, 'tis not possible :) - Gregor Richards
Dec 07 2008