Thread overview | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 28, 2020 Call method if declared only | ||||
---|---|---|---|---|
| ||||
Searching solution for idea ! Goal is to get System message, dispatch/route to method ! If method implemented only ! I dream on in future write clean code of a derived widgets like this : class Base { // dispatch void On( message ... ) { // call On<message>() // example: call OnKeyUp() - if method OnKeyUp() is exists only } } class Derived : Base { // method implementation void OnKeyUp( ... ) { // } } I tryed code like this: import core.sys.windows.windows; import std.stdio; class Base { LRESULT On( UINT message, WPARAM wParam, LPARAM lParam ) { switch ( message ) { case WM_KEYDOWN: OnWM_KEYDOWN( wParam, lParam ); // <-- but it required declared OnWM_KEYDOWN(...) in base class Base. How will be without declaring in Base ? break; default: } } } class Button : Base { LRESULT OnWM_KEYDOWN( WPARAM wParam, LPARAM lParam ) { writeln( "WM_KEYDOWN" ); } } May be other than derived ? May be templating ? How to implement ? |
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote:
> Searching solution for idea !
>
> Goal is to get System message, dispatch/route to method !
> If method implemented only !
>
> I dream on in future write clean code of a derived widgets like this :
>
> class Base
> {
> // dispatch
> void On( message ... )
> {
> // call On<message>()
> // example: call OnKeyUp() - if method OnKeyUp() is exists only
> }
> }
>
> class Derived : Base
> {
> // method implementation
> void OnKeyUp( ... )
> {
> //
> }
> }
>
>
>
> I tryed code like this:
>
> import core.sys.windows.windows;
> import std.stdio;
>
>
> class Base
> {
> LRESULT On( UINT message, WPARAM wParam, LPARAM lParam )
> {
> switch ( message )
> {
> case WM_KEYDOWN:
> OnWM_KEYDOWN( wParam, lParam );
> // <-- but it required declared OnWM_KEYDOWN(...) in base class Base. How will be without declaring in Base ?
> break;
>
> default:
> }
> }
> }
>
>
> class Button : Base
> {
> LRESULT OnWM_KEYDOWN( WPARAM wParam, LPARAM lParam )
> {
> writeln( "WM_KEYDOWN" );
> }
> }
>
>
> May be other than derived ? May be templating ?
> How to implement ?
Now I go in ths way:
import std.stdio;
import std.traits;
class Base
{
void On( alias THIS )( int message )
{
static if (
__traits( hasMember, THIS, "OnKey" ) &&
isCallable!( __traits( getMember, THIS, "OnKey" ) )
)
{
__traits( getMember, THIS, "OnKey" )();
}
}
void run( alias THIS )()
{
On!THIS( 1 );
}
}
class A : Base
{
void OnKey()
{
writeln( "A.OnKey()" );
}
}
void main()
{
auto a = new A();
a.run!a();
}
Searching for beauty readable code...
|
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On Friday, 28 February 2020 at 08:08:59 UTC, Виталий Фадеев wrote: > On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote: >> Searching solution for idea ! >> >> Goal is to get System message, dispatch/route to method ! >> If method implemented only ! >> >> I dream on in future write clean code of a derived widgets like this : >> >> class Base >> { >> // dispatch >> void On( message ... ) >> { >> // call On<message>() >> // example: call OnKeyUp() - if method OnKeyUp() is exists only >> } >> } >> >> May be other than derived ? May be templating ? >> How to implement ? > > Now I go in ths way: [snip] > Searching for beauty readable code... Here's an attempt. It looks up all subclasses of Base in the same module, and calls the named method if it exists. However, it will fail for any subclass of Base that is defined in a different module. 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); } -- Simen |
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On Friday, 28 February 2020 at 08:08:59 UTC, Виталий Фадеев wrote: > Searching for beauty readable code... The pattern throughout Phobos is static tests, like isInputRange!R So something like this: import std.stdio; import std.traits; template canOnKey(T) { static if (__traits(hasMember, T, "onKey")) enum canOnKey = isCallable!(__traits(getMember, T, "onKey")); else enum canOnKey = false; } struct A { void onKey() { writeln("called A"); } } struct B { } struct C { bool onKey = false; } void maybeKey(T)(T o) if (canOnKey!T) { o.onKey(); } void maybeKey(T)(T o) if (!canOnKey!T) { } void main() { auto a = A(), b = B(), c = C(); maybeKey(a); maybeKey(b); maybeKey(c); } output: called A (and no other output) Of course in this exact instance it would be simpler to write void maybeKey(T)(T o) { static if (canOnKey!T) o.onKey(); } And rather than lots of specific hasThisExactMethod!T tests, it might be nice if in your actual program there's a 'class' of grouped properties that you can test for all at once, again like isInputRange!T and friends. |
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to mipri | On Friday, 28 February 2020 at 08:36:53 UTC, mipri wrote:
> On Friday, 28 February 2020 at 08:08:59 UTC, Виталий Фадеев wrote:
>> [...]
>
> The pattern throughout Phobos is static tests, like isInputRange!R
>
> [...]
It cool !
I will try !
Thank you !
|
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | 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 |
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | 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!
|
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On 2/28/20 12:25 PM, Виталий Фадеев wrote: > > Now I reading Template doc for up skill... > I recommend this nice tutorial https://github.com/PhilippeSigaud/D-templates-tutorial |
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев wrote: > 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... So let's create a template for that: interface IMessageHandler(alias msg) { mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM wParam, LPARAM lParam);"); } And use it: import core.sys.windows.windows; import std.stdio; class Base { LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_KEYDOWN: if (auto that = cast(IMessageHandler!WM_KEYDOWN)this) { return that.OnWM_KEYDOWN(wParam, lParam); } break; default: } return 0; } } class Button : Base, IMessageHandler!WM_KEYDOWN { 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); } You'll still have to specify for each derived class which messages they handle, but no need to define hundreds of interfaces separately. -- Simen |
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Friday, 28 February 2020 at 09:49:53 UTC, Simen Kjærås wrote:
> On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев wrote:
>> [...]
>
> So let's create a template for that:
>
> [...]
Cool!
|
Copyright © 1999-2021 by the D Language Foundation