www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - I have a problem with D

reply Adam Sansier <Adam.Sansier gmail.com> writes:
Hi,

I have designed a class based system that involves 
self-delegation instead of override.

It is similar to event based programming.

I have defined an event as a container type that holds 
functions(or possibly delegates, but the desire is to avoid them).



class Base
{
    alias EventMethod = void function(Base _this);
    public Event!EventMethod MyEvents

    public MyEvent()
    {
        // Go ahead and inform subscribed handlers
        MyEvents(this);

        // Do other stuff here
    }
}

The outside world can attach their own method to the event as 
normal. They act as effective members to Base but with only 
access to public members.

Now, the normal workflow in OOP is to derive from Base

class Derived : Base
{

    public override MyEvent()
    {
       // must call super.TriggerMyEvents for design to work, else 
events won't be called. This is dangerous

       // Other work done here.
    }
}


To prevent the dangerous scenario of the deriving user from not 
calling the base class method, the workflow is changed to

class Derived : Base
{
     public static myEvent(Derived _this)
     {
         // Other work done here
     }

     this()
     {
        // Subscribe to Base's MyEvent
        MyEvents += &myEvent;
     }

}

The idea is that the Derived type tries to behave as much as 
possible like a non-derived type when it can. This separates 
certain behaviors from the base class. It helps in other areas of 
the design(because then those behaviors can be reused since they 
do not directly depend on the base type). It also free's up the 
methods to be overridable if necessary without breaking the event 
processing, since now the event processing is mainly done through 
subscriber model. Also, The derived class or anyone else can now 
unhook it's own event handling. If we need to temporarily 
"un-override" some behavior, we cannot do this in the inheritance 
model without mucking with the VTable which is dangerous.

Problems with this setup that are unfortunate but seem to be due 
to language limitations and no fundamental reasons:

If myEvent is static:

1. myEvent cannot use this, but _this is functionally the same. 
We have to prepend every access to the object's members with 
_this. It becomes very ugly code.

2. We also can only access public members because it is not a 
dynamic member. Yet it is clear that myEvent, being defined 
inside the class and having a _this ptr is meant to have full 
access like any normal member.

If myEvent is non-static:

1. Since Event only takes functions, we cannot directly add to 
it. There are some nasty hacks that seem to work but they have 
created other problems in the design.

2. It then invokes the GC even though there is no reason this is 
required. The design supplies the this ptr.


---

One has an either or situation here and neither are desirable.

It seems that D can do better.


1. Allow for module level, static member functions with a special 
_this parameter to act as a in between a function and a delegate. 
this = _this inside the body and has the class/struct type. The 
only difference between this an C++ delegates is that _this is 
explicitly passable.

This avoids the need to prefix _this to every member access.

2. Allow for C++ delegate style method. This is essentially 1 but 
hides the explicit passing of _this. It can be hacked though.

3. Allow access to private members of the enclosing type. For all 
practical purposes, it is part of the class construction and does 
not need to have the members hidden from it. It is both inside 
the module and inside the type and has a this type of parameter. 
It should be a first class citizen then.

4. Allow these new method types to be virtual. This is a bit of 
complexity that might not be desirable at this point though, but 
would allow them to be extended instead of acting like static or 
final methods.

The goal being to allow for derived types to participate in the 
oop hierarchy as general types do but to have special privileges. 
Maybe only protected members could be accessed by _this to allow 
for some level of control(but somewhat meaningless I believe).



These functions should be implicitly convertible to a function 
with first parameter of the class/struct type.

Maybe there is a cleaner way to accomplish this with templates 
though. I believe it essentially requires the assignment to this 
though, which I believe is illegal?



























import std.stdio;


class Event(T, P)
{
	T[] callbacks;

	void opCall(P p)
	{
		foreach(e; callbacks)
			e(p);
	}

	void opOpAssign(string op, T)(T c)
	{
		static if (op == "~")
			callbacks ~= c;
	}
}


class Base
{
	string test = "This is a test, only a test!";
	alias EventMethod = void function(Base _this);
	//alias EventMethod = void delegate(Base _this);
	auto MyEvents = new Event!(EventMethod, Base)();

	void MyEvent()
	{
		MyEvents(this);
	}

	void MyEventTrigger()
	{
		MyEvents(this);
	}
}

class Derived : Base
{

	this()
	{	
		MyEvents ~= cast(void function(Base 
_this))(cast(void*)&myEventHandler);		// Notice the ugly hack to 
insert our event hanlder but works
		//MyEvents ~= cast(void delegate(Base 
_this))(cast(void*)&myEventHandler);      // can't cast! 
depreciated
	}

	override void MyEvent()
	{
		// Oops, what if we forgot to call base or did something hokey?
	}

	// Lets keep things separated
	static void myEventHandler(Derived _this)	// If not static and 
function events used, crashes.
	{
		writeln("Hello D-World! " ~ _this.test);
	}

}

int main(string[] argv)
{
	
     auto d = new Derived();
	
	d.MyEvent();   // Oops, nothing!!!
	d.MyEventTrigger();  // Better!


     return 0;
}
Jun 27 2016
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 28/06/2016 4:37 PM, Adam Sansier wrote:
 Hi,

 I have designed a class based system that involves self-delegation
 instead of override.

 It is similar to event based programming.

 I have defined an event as a container type that holds functions(or
 possibly delegates, but the desire is to avoid them).



 class Base
 {
    alias EventMethod = void function(Base _this);
    public Event!EventMethod MyEvents

    public MyEvent()
    {
        // Go ahead and inform subscribed handlers
        MyEvents(this);

        // Do other stuff here
    }
 }

 The outside world can attach their own method to the event as normal.
 They act as effective members to Base but with only access to public
 members.

 Now, the normal workflow in OOP is to derive from Base

 class Derived : Base
 {

    public override MyEvent()
    {
       // must call super.TriggerMyEvents for design to work, else events
 won't be called. This is dangerous

       // Other work done here.
    }
 }


 To prevent the dangerous scenario of the deriving user from not calling
 the base class method, the workflow is changed to

 class Derived : Base
 {
     public static myEvent(Derived _this)
     {
         // Other work done here
     }

     this()
     {
        // Subscribe to Base's MyEvent
        MyEvents += &myEvent;
     }

 }

 The idea is that the Derived type tries to behave as much as possible
 like a non-derived type when it can. This separates certain behaviors
 from the base class. It helps in other areas of the design(because then
 those behaviors can be reused since they do not directly depend on the
 base type). It also free's up the methods to be overridable if necessary
 without breaking the event processing, since now the event processing is
 mainly done through subscriber model. Also, The derived class or anyone
 else can now unhook it's own event handling. If we need to temporarily
 "un-override" some behavior, we cannot do this in the inheritance model
 without mucking with the VTable which is dangerous.

 Problems with this setup that are unfortunate but seem to be due to
 language limitations and no fundamental reasons:

 If myEvent is static:

 1. myEvent cannot use this, but _this is functionally the same. We have
 to prepend every access to the object's members with _this. It becomes
 very ugly code.
Well yeah, that's how function pointers work. Hence why we have delegates.
 2. We also can only access public members because it is not a dynamic
 member. Yet it is clear that myEvent, being defined inside the class and
 having a _this ptr is meant to have full access like any normal member.
Not sure about protected, but private members definitely should be accessible from such a method. Since it is in the same module as the module.
 If myEvent is non-static:

 1. Since Event only takes functions, we cannot directly add to it. There
 are some nasty hacks that seem to work but they have created other
 problems in the design.
Well that's easy fixed. Don't use function pointers since you need a context pointer too.
 2. It then invokes the GC even though there is no reason this is
 required. The design supplies the this ptr.
Well of course it does, you're allocating via the GC.
 ---

 One has an either or situation here and neither are desirable.

 It seems that D can do better.


 1. Allow for module level, static member functions with a special _this
 parameter to act as a in between a function and a delegate. this = _this
 inside the body and has the class/struct type. The only difference
 between this an C++ delegates is that _this is explicitly passable.

 This avoids the need to prefix _this to every member access.

 2. Allow for C++ delegate style method. This is essentially 1 but hides
 the explicit passing of _this. It can be hacked though.

 3. Allow access to private members of the enclosing type. For all
 practical purposes, it is part of the class construction and does not
 need to have the members hidden from it. It is both inside the module
 and inside the type and has a this type of parameter. It should be a
 first class citizen then.

 4. Allow these new method types to be virtual. This is a bit of
 complexity that might not be desirable at this point though, but would
 allow them to be extended instead of acting like static or final methods.

 The goal being to allow for derived types to participate in the oop
 hierarchy as general types do but to have special privileges. Maybe only
 protected members could be accessed by _this to allow for some level of
 control(but somewhat meaningless I believe).



 These functions should be implicitly convertible to a function with
 first parameter of the class/struct type.

 Maybe there is a cleaner way to accomplish this with templates though. I
 believe it essentially requires the assignment to this though, which I
 believe is illegal?



























 import std.stdio;


 class Event(T, P)
 {
     T[] callbacks;

     void opCall(P p)
     {
         foreach(e; callbacks)
             e(p);
     }

     void opOpAssign(string op, T)(T c)
     {
         static if (op == "~")
             callbacks ~= c;
     }
 }


 class Base
 {
     string test = "This is a test, only a test!";
     alias EventMethod = void function(Base _this);
     //alias EventMethod = void delegate(Base _this);
     auto MyEvents = new Event!(EventMethod, Base)();

     void MyEvent()
     {
         MyEvents(this);
     }

     void MyEventTrigger()
     {
         MyEvents(this);
     }
 }

 class Derived : Base
 {

     this()
     {
         MyEvents ~= cast(void function(Base
 _this))(cast(void*)&myEventHandler);        // Notice the ugly hack to
 insert our event hanlder but works
         //MyEvents ~= cast(void delegate(Base
 _this))(cast(void*)&myEventHandler);      // can't cast! depreciated
     }

     override void MyEvent()
     {
         // Oops, what if we forgot to call base or did something hokey?
     }

     // Lets keep things separated
     static void myEventHandler(Derived _this)    // If not static and
 function events used, crashes.
     {
         writeln("Hello D-World! " ~ _this.test);
     }

 }

 int main(string[] argv)
 {

     auto d = new Derived();

     d.MyEvent();   // Oops, nothing!!!
     d.MyEventTrigger();  // Better!


     return 0;
 }
Please jump on IRC (Freenode #d) at some point, it'll be much easier to discuss this there and come up with an actual solution for your needs.
Jun 27 2016
prev sibling next sibling parent Stefan <stefan schuerger.com> writes:
On Tuesday, 28 June 2016 at 04:37:34 UTC, Adam Sansier wrote:
 Hi,

 I have designed a class based system that involves 
 self-delegation instead of override.

 It is similar to event based programming.

 I have defined an event as a container type that holds 
 functions(or possibly delegates, but the desire is to avoid 
 them).
Hi Adam, The easiest way to enforce calling of base class's method is to make it final and to offer additional functionality only in an optional extra method: class Base { alias EventMethod = void function(Base _this); public Event!EventMethod MyEvents final public MyEvent() { // Go ahead and inform subscribed handlers MyEvents(this); EventExtras(this); } protected void EventExtras() {} // empty in the base class } class Derived : Base { protected override void EventExtras() { // This does not need to call super.MyEvent // Other work done here. } } Does this help?
Jun 28 2016
prev sibling parent Bienlein <jeti789 web.de> writes:
You can make use of the visitor pattern. The user that created 
some subclass then only needs to fill the visitor method with 
some stuff and that's it. The visitor was already initialized 
when created which happened before it was handed in to the 
visitor method of the subclass as a method parameter and things 
are fine.

-- Bienlein
Jun 29 2016