Games people play

Bill Baxter dnewsgroup at billbaxter.com
Wed Oct 4 00:39:35 PDT 2006


Walter Bright wrote:
> Bill Baxter wrote:
>> So instead of
>> template Signal(T1) // for one argument ...
>> template Signal(T1, T2) // for two arguments ...
>> template Signal(T1, T2, T3) // for three arguments ...
>> template Signal(T1, T2, T3, T4) // for four arguments ...
>> template Signal(T1, T2, T3, T4, T5) // for five arguments ...
>> template Signal(T1, T2, T3, T4, T5, T6) // for six arguments ...
>> template Signal(etc...
>>
>> You can just have one template
>> template Signal(...) // for any number of arguments ...
> 
> That would be better, but the user doesn't see that code, just the 
> library implementer. So it isn't so bad.

Well I may be crazy, but I tend to prefer using libraries with readable 
code.  It makes things so much easier to debug when something goes 
wrong.  I cringe every time I have some crash inside of STL or some 
Boost library in C++.  The code is just terrible for readability.  Yes, 
ideally I shouldn't have to care how it's implemented, but in practice 
every once in a while it is useful to be able to actually read the code.

But you are right, it is not a show-stopper.  Just makes it less 
convenient, and makes it look like it was implemented more "despite" the 
language than "thanks to" it.

>> But something more is needed for Dynamic Qt-like S&S.  Some sort of 
>> compile-time introspection seems a minimal requirement.  I think some 
>> way to tag particular method like Qt's "slot:" keyword will also be 
>> necessary to make it usable.  Anyway you need some way to say "do 
>> something with this method" and do it at the point of declaration 
>> rather than in the constructor or elsewhere.
> 
> I don't understand. Exactly what needs to be done at compile time that 
> can't be done with the mixin method?

The mixins are fine for Signals, but I'm talking about a dynamically 
callable method, or Qt-like "slot".  I was assuming a world in which 
methods are not dynamically callable by default, as is the case with 
current C++/Qt.  In that case, the Qt way is for users to flag methods 
that should have extra runtime call-by-name code generated for them by 
putting the 'slots:' keyword before the method(s).  Then the "moc" 
compiler generates this code.

I believe it's already possible with templates to make a method callable 
by name if you provide a name to use, and call some sort of 
register!(method, "method") template.  PyD does a related kind of thing, 
and I wrote my own dynamic sigslot implementation in C++ that does that 
(quite hacky, but it works), so it must be possible in D too.  But 
having to call "register!(...)" somewhere is not as convenient (or as 
easy to maintain) as just being able to flag the method right at the 
place of declaration.


Of course the outside-the-class "register!()" technique is useful too, 
for those cases where you can't modify the class's code for whatever reason.

--bb


For kicks, here's a snippet of my dynamic sigslot implementation in C++.
I gave up after 4 arguments because it became too tedious and too much 
of an eyesore.  I was originally planning to do 9.

   template <class ClassT>
   class _SlotCaller0 : public _SlotCaller<ClassT>
   {
   protected:    typedef void (ClassT::*MethT)();
     MethT mMeth; friend DynSigSlot;
     _SlotCaller0(ClassT* obj, MethT m) : _SlotCaller<ClassT>(obj), 
mMeth(m) {}
     virtual void call(va_list args) {
       (mObj->*mMeth)();
     }
   };
   template <class ClassT, class Arg1T>
   class _SlotCaller1 : public _SlotCaller<ClassT> {
   protected:  typedef void (ClassT::*MethT)(Arg1T);
     MethT mMeth;  friend DynSigSlot;
     _SlotCaller1(ClassT* obj, MethT m) : _SlotCaller<ClassT>(obj), 
mMeth(m) {}
     virtual void call(va_list args) {
       Arg1T a1 = DSS_VARG(args,Arg1T);
       (mObj->*mMeth)( a1 );
     }
   };
   template <class ClassT, class Arg1T, class Arg2T>
   class _SlotCaller2 : public _SlotCaller<ClassT> {
   protected:    typedef void (ClassT::*MethT)(Arg1T,Arg2T);
     MethT mMeth; friend DynSigSlot;
     _SlotCaller2(ClassT* obj, MethT m) : _SlotCaller<ClassT>(obj), 
mMeth(m) {}
     virtual void call(va_list args) {
       Arg1T a1 = DSS_VARG(args, Arg1T); Arg2T a2 = DSS_VARG(args, Arg2T);
       (mObj->*mMeth)( a1, a2 );
     }
   };
   template <class ClassT, class Arg1T, class Arg2T, class Arg3T>
   class _SlotCaller3 : public _SlotCaller<ClassT> {
   protected:    typedef void (ClassT::*MethT)(Arg1T,Arg2T,Arg3T);
     MethT mMeth; friend DynSigSlot;
     _SlotCaller3(ClassT* obj, MethT m) : _SlotCaller<ClassT>(obj), 
mMeth(m) {}
     virtual void call(va_list args) {
       Arg1T a1 = DSS_VARG(args, Arg1T); Arg2T a2 = DSS_VARG(args, Arg2T);
       Arg3T a3 = DSS_VARG(args, Arg3T);
       (mObj->*mMeth)( a1, a2, a3 );
     }
   };
   template <class ClassT, class Arg1T, class Arg2T, class Arg3T, class 
Arg4T>
   class _SlotCaller4 : public _SlotCaller<ClassT> {
   protected:   typedef void (ClassT::*MethT)(Arg1T,Arg2T,Arg3T,Arg4T);
     MethT mMeth; friend DynSigSlot;
     _SlotCaller4(ClassT* obj, MethT m) : _SlotCaller<ClassT>(obj), 
mMeth(m) {}
     virtual void call(va_list args) {
       Arg1T a1 = DSS_VARG(args, Arg1T); Arg2T a2 = DSS_VARG(args, Arg2T);
       Arg3T a3 = DSS_VARG(args, Arg3T); Arg4T a4 = DSS_VARG(args, Arg4T);
       (mObj->*mMeth)( a1, a2, a3, a4 );
     }
   };



More information about the Digitalmars-d mailing list