www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - delegate bug?

reply "Jack Applegame" <japplegame gmail.com> writes:
This code:

import std.stdio;
class A {
   void func() { writeln("A"); }
}
class B : A {
   override void func() { writeln("B"); }
}
void main() {
   A a = new A;
   B b = new B;

   auto dg = &a.func;
   dg();

   dg.ptr = cast(void*)b;
   dg();
}

outputs:
A
A

but expected:
A
B
Nov 09 2012
next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
Windows dmd 2.060
Nov 09 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-11-09 14:36, Jack Applegame wrote:
 This code:

 import std.stdio;
 class A {
    void func() { writeln("A"); }
 }
 class B : A {
    override void func() { writeln("B"); }
 }
 void main() {
    A a = new A;
    B b = new B;

    auto dg = &a.func;
    dg();

    dg.ptr = cast(void*)b;
    dg();
 }

 outputs:
 A
 A

 but expected:
 A
 B
This is expected behavior. Delegates do not perform any dynamic dispatch. The method that is called is chosen when the delegate is created, i.e. "auto dg = &a.func;" You can workaround this by calling another method in "A" that will call the actual method you want to call, something like this: class A { void resolveVirtualCall () { func(); } } auto dg = &a.resolveVirtualCall; -- /Jacob Carlborg
Nov 09 2012
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Jack Applegame wrote:

    dg.ptr = cast(void*)b;
This changes the environment only. It does not change the function called on the``dg()'-request---and the function called does not depend on the environment. But including a dependence on the environment may not change the output, because the compiler may instruct the executable to memoize the output. Hint: casting is equivalent to exclaiming: "I know what I am doing. Therefore: shut up compiler!" .manfred
Nov 09 2012
parent reply "Jack Applegame" <japplegame gmail.com> writes:
Ok. Then how to implement in D this С++ std::function feature?

http://liveworkspace.org/code/01aa058901529f65cb9a3cc4ba605248
Nov 09 2012
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Jack Applegame wrote:

 Ok. Then how to implement in D this С++ std::function feature?
 
 http://liveworkspace.org/code/01aa058901529f65cb9a3cc4ba605248
That feature is among others defined here: http://en.cppreference.com/w/cpp/utility/functional/function As one might see it is a template, defined in a library. Therefore the first question is, wether D has a similar template in a library---and secondly: without such a template in a library: how to implement the base functionality in a non-generic case. Because this is a learning group and not a teaching group--and you did not report on your fruitless tries: go on. -manfred
Nov 09 2012
next sibling parent reply "Jack Applegame" <japplegame gmail.com> writes:
 Because this is a learning group and not a teaching group--and 
 you did
 not report on your fruitless tries: go on.

 -manfred
This is not only std::function feature. In C++ we can call member-function by combining potinter to object and pointer to function: http://liveworkspace.org/code/1fe3107cf3a311aa95cb9fc62b9117a7 I have no idea how to do somethink like that in D.
Nov 09 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/09/2012 07:49 PM, Jack Applegame wrote:
 Because this is a learning group and not a teaching group--and you did
 not report on your fruitless tries: go on.

 -manfred
This is not only std::function feature. In C++ we can call member-function by combining potinter to object and pointer to function: http://liveworkspace.org/code/1fe3107cf3a311aa95cb9fc62b9117a7 I have no idea how to do somethink like that in D.
auto memberFunctionPointer = function(X receiver, A arg0, B arg1, C arg2)=>receiver.memberFunction(arg0, arg1, arg2); This strategy is also the best way for a C++ compiler to implement a standard conformant member function pointer behind the scenes, so you lose nothing.
Nov 09 2012
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 11/09/2012 10:30 AM, Manfred Nowak wrote:
 Jack Applegame wrote:

 Ok. Then how to implement in D this С++ std::function feature?

 http://liveworkspace.org/code/01aa058901529f65cb9a3cc4ba605248
That feature is among others defined here: http://en.cppreference.com/w/cpp/utility/functional/function
The following D program produces the same output as the C++ example there: import std.stdio : writeln; import std.functional : curry; struct Foo { int num; void print_add(int i) { writeln(num + i); } } void print_num(int i) { writeln(i); } void main() { // store a free function auto f_display = &print_num; f_display(-9); // store a lambda auto f_display_42 = { print_num(42); }; f_display_42(); // store a curried call alias curry!(print_num, 31337) f_display_31337; f_display_31337(); // store a call to a member function auto f_add_display = (Foo foo, int i) { return foo.print_add(i); }; auto foo = Foo(314159); f_add_display(foo, 1); } D has more features: // store a call to a member function on a particular object auto f_print_add_on_object = &foo.print_add; f_print_add_on_object(2); There is also std.functional.toDelegate: http://dlang.org/phobos/std_functional.html#toDelegate Ali
Nov 09 2012
parent reply "Jack Applegame" <japplegame gmail.com> writes:
Ok. I will try to explain what exactly i need.

import std.stdio;

import std.stdio;

class Figure {
   void draw(){}
   void erase(){}
}

class Circle : Figure {
   override void draw() { writeln("drawing circle"); }
   override void erase() { writeln("erasing circle"); }
}

class Square : Figure {
   override void draw() { writeln("drawing square"); }
   override void erase() { writeln("erasing square"); }
}

class Triangle : Figure {
   override void draw() { writeln("drawing triangle"); }
   override void erase() { writeln("erasing triangle"); }
}

void main() {
   Figure[] figures;
   createFigures(figures);
   doAction(figures, &Figure.draw);
   doAction(figures, &Figure.erase);
}

void doAction(Figure[] figures, void function() action) {
   foreach(Figure figure; figures) {
     // how to do action with figure???
   }
}

void createFigures(ref Figure[] figures) {
   figures ~= new Circle;
   figures ~= new Square;
   figures ~= new Triangle;
}
Nov 09 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/09/2012 09:13 PM, Jack Applegame wrote:
 Ok. I will try to explain what exactly i need.

 ...
The following works. You can also use a (scoped) delegate in order to allow the caller to close over his context. import std.stdio; class Figure { void draw(){} void erase(){} } class Circle : Figure { override void draw() { writeln("drawing circle"); } override void erase() { writeln("erasing circle"); } } class Square : Figure { override void draw() { writeln("drawing square"); } override void erase() { writeln("erasing square"); } } class Triangle : Figure { override void draw() { writeln("drawing triangle"); } override void erase() { writeln("erasing triangle"); } } void main() { Figure[] figures; createFigures(figures); doAction(figures, x=>x.draw()); doAction(figures, x=>x.erase()); } void doAction(Figure[] figures, void function(Figure) action) { foreach(Figure figure; figures) { action(figure); } } void createFigures(ref Figure[] figures) { figures ~= new Circle; figures ~= new Square; figures ~= new Triangle; }
Nov 09 2012
parent reply "Jack Applegame" <japplegame gmail.com> writes:
On Friday, 9 November 2012 at 20:22:40 UTC, Timon Gehr wrote:
 The following works. You can also use a (scoped) delegate in 
 order to allow the caller to close over his context.
Wow! Great! Thanks. But I can't understend this syntax: x=>x.draw() Where i can read about it?
Nov 09 2012
next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
I have found it. This is shorthand lambda syntax.
Nov 09 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-11-09 21:31, Jack Applegame wrote:

 Wow! Great! Thanks.
 But I can't understend this syntax:
 x=>x.draw()


 Where i can read about it?
It's a delegate literal, or also known as a lambda. http://dlang.org/expression.html#Lambda -- /Jacob Carlborg
Nov 09 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/09/2012 09:31 PM, Jack Applegame wrote:
 On Friday, 9 November 2012 at 20:22:40 UTC, Timon Gehr wrote:
 The following works. You can also use a (scoped) delegate in order to
 allow the caller to close over his context.
Wow! Great! Thanks. But I can't understend this syntax: x=>x.draw() Where i can read about it?
It is a lambda function literal. It is as if you did static void action(Figure x){ return x.draw(); } doAction(figures, &action); which can also be written in any of the following ways. Because the types are mandated by the function that is called, you can leave them out: doAction(figures, function void(Figure x){ return x.draw(); }); // function literal doAction(figures, function(x){ return x.draw(); }); // infer types doAction(figures, (x){ return x.draw(); }); // infer 'function' doAction(figures, (x)=>x.draw()); // convenient lambda syntax doAction(figures, x=>x.draw()); // also without parentheses It is documented here (scroll up a bit, Lambda does not seem to have an anchor) http://dlang.org/expression.html#FunctionLiteral In this case, we used the feature to implement a member function pointer, but there are many more applications that such a shorthand syntax makes convenient. It might generally be helpful for your programming skills to get accustomed to functional programming a bit. So in case you are interested, I suggest you consult your search engine of choice about the subject. You could eg. look into Scheme and/or Haskell and try to reproduce some of the examples also in D.
Nov 09 2012