Call method if declared only

Виталий Фадеев vital.fadeev at gmail.com
Fri Feb 28 09:25:58 UTC 2020


On Friday, 28 February 2020 at 09:12:38 UTC, Simen Kjærås wrote:
> On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев 
> wrote:
>> Searching solution for idea !
>
> For whatever reason, it seems my attempts at answering this 
> earlier has disappeared into the void. Here:
>
> import core.sys.windows.windows;
> import std.stdio;
>
> class Base {
>     LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
>         switch (message) {
>             case WM_KEYDOWN:
>                 return tryCall!"OnWM_KEYDOWN"(wParam, lParam);
>             default:
>         }
>         return 0;
>     }
>
>     auto tryCall(string name, Args...)(Args args) {
>         import std.meta;
>
>         alias This = typeof(this);
>         alias module_ = __traits(parent, This);
>
>         enum isSubclass(T...) = is(T[0] : This);
>         alias getModuleMember(string name) = 
> __traits(getMember, module_, name);
>         enum hasMethod(T) = __traits(hasMember, T, name);
>
>         // Get every member in this module
>         enum memberNames = __traits(allMembers, module_);
>         alias members = staticMap!(getModuleMember, 
> memberNames);
>
>         // Filter away anything that isn't derived from Base
>         alias subclasses = Filter!(isSubclass, members);
>
>         // Get rid of anything that doesn't have a method with 
> the correct name
>         alias subclassesWithMethod = Filter!(hasMethod, 
> subclasses);
>
>         // Sort them so you get the most derived types first
>         alias Types = DerivedToFront!subclassesWithMethod;
>
>         // Check for each type if the `this` is an instance of 
> that specific one
>         static foreach (T; Types) {
>             if (cast(T)this !is null) {
>                 // And look up that method and call it.
>                 return __traits(getMember, cast(T)this, 
> name)(args);
>             }
>         }
>
>         // If `this` is not one of the types with that method, 
> return some default value
>         return 0;
>     }
> }
>
> class Button : Base {
>     LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
>         writeln("WM_KEYDOWN");
>         return 0;
>     }
> }
>
> unittest {
>     Base b1 = new Base();
>     Base b2 = new Button();
>
>     writeln("Base:");
>     b1.On(WM_KEYDOWN, 0, 0);
>     writeln("Button:");
>     b2.On(WM_KEYDOWN, 0, 0);
> }
>
> Now, this only works for subclasses defined in the same module. 
> A possibly better solution would be interfaces:
>
> import core.sys.windows.windows;
> import std.stdio;
>
> class Base {
>     LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
>         switch (message) {
>             case WM_KEYDOWN:
>                 if (cast(IKeyDown)this) {
>                     return 
> (cast(IKeyDown)this).OnWM_KEYDOWN(wParam, lParam);
>                 }
>             default:
>         }
>         return 0;
>     }
> }
>
> interface IKeyDown {
>     LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam);
> }
>
> class Button : Base, IKeyDown {
>     LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
>         writeln("WM_KEYDOWN");
>         return 0;
>     }
> }
>
> unittest {
>     Base b1 = new Base();
>     Base b2 = new Button();
>
>     writeln("Base:");
>     b1.On(WM_KEYDOWN, 0, 0);
>     writeln("Button:");
>     b2.On(WM_KEYDOWN, 0, 0);
> }
>
> --
>   Simen

Yes. Thank !
I read it.
Problem is - OS has many messages + user messages... It mean what 
interfaces like IKeyDown must me declared. All. Dream on write 
less code...

Some like code generation. In message dispatcher. Like this:

     import core.sys.windows.windows;
     import std.stdio;
     import std.traits;


     template canOn( T, M )
     {
         enum string callbackName = "On" ~ __traits( identifier, M 
);

         static if ( __traits( hasMember, T, callbackName ) )
             enum canOn = isCallable!( __traits( getMember, T, 
callbackName ) );
         else
             enum canOn = false;
     }

     void maybeOn( T, alias M )( T o, M message )
     {
         enum string callbackName = "On" ~ __traits( identifier, M 
);

         static if ( canOn!(T, M) )
             __traits( getMember, T, callbackName )();
     }


     void On( T, alias M )( T o, M message )
     {
         o.maybeOn( message );
     }


     class Base
     {
         void Send( T, alias M )( T o, M message )
         {
             // generate code in dispatcher
             // if ( canOn!( T, M ) )
             //   writeCode(
             //     q{
             //        if ( message == WM_KEYUP )
             //           o.OnWM_KEYUP();
             //      }
             //   );
             o.On( message );
         }
     }

     class A : Base
     {
         void OnWM_KEYUP()
         {
             writeln( "A.OnKey()" );
         }
     }


     void main()
     {
         auto a = new A();
         a.Send( a, WM_KEYUP );
     }


Here I have compile error... at
     void On( T, alias M )( T o, M message )

Now I reading Template doc for up skill...

Thank!


More information about the Digitalmars-d-learn mailing list