www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Method pointers are *function* pointers?? Or delegates??

reply "Mehrdad" <wfunction hotmail.com> writes:
My brain just exploded.
Can someone explain what's going on?

class Test
{
	public void foo() { }
}

static assert(is(typeof(&Test.foo) == void function()));
May 18 2012
next sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 18-05-2012 20:22, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Delegates. Pointer to member function + class instance. -- Alex Rønne Petersen alex lycus.org http://lycus.org
May 18 2012
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static. Andrei
May 18 2012
next sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 18-05-2012 21:34, Steven Schveighoffer wrote:
 On Fri, 18 May 2012 15:17:28 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Friday, 18 May 2012 at 18:59:23 UTC, Steven Schveighoffer wrote:
 On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug. The purpose is so you can get the function pointer portion of a delegate without an instance of the object.

I actually realized that might be the reason before I reported this, but then I thought: In that case, shouldn't the 'this' parameter be explicitly part of the function (at the end of the parameter list)?

That would be nice, wouldn't it? :) -Steve

At least it would prevent writing platform/compiler-specific code... -- Alex Rønne Petersen alex lycus.org http://lycus.org
May 18 2012
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/18/12 1:59 PM, Steven Schveighoffer wrote:
 On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug.

It is.
 The purpose is so you can get the function pointer portion of a delegate
 without an instance of the object.

Typing is what it is. The following program is unsound without a cast in sight: class Test { void foo() { writeln("foo"); } } static assert(is(typeof(&Test.foo) == void function())); void fun() { writeln("fun"); } void main() { alias void function() TFun; TFun a = &fun; a(); a = &Test.foo; a(); } At best things could be arranged that &Test.foo has type void function(Test) or something. Andrei
May 18 2012
next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 18/05/2012 22:35, Andrei Alexandrescu a écrit :
 On 5/18/12 1:59 PM, Steven Schveighoffer wrote:
 On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug.

It is.
 The purpose is so you can get the function pointer portion of a delegate
 without an instance of the object.

Typing is what it is. The following program is unsound without a cast in sight: class Test { void foo() { writeln("foo"); } } static assert(is(typeof(&Test.foo) == void function())); void fun() { writeln("fun"); } void main() { alias void function() TFun; TFun a = &fun; a(); a = &Test.foo; a(); } At best things could be arranged that &Test.foo has type void function(Test) or something. Andrei

It would be nice, but require a way to express that calling convention (thiscall is often different than simply passing an argument). I proposed extern(this). This would have the extra benefice of being able to declare UFCS with thiscall convention. If the extern isn't added, the feature must go, it is made to write bugs.
May 19 2012
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-05-22 20:14, Steven Schveighoffer wrote:

 I agree, it's unsound. But so is this:

 int *blah = void;

 *blah = 5;

 It doesn't mean that the language should forbid it, or that the compiler
 isn't implemented as designed.

 At the *very least*, the address to member function operation should be
 illegal in  safe code.

 At best things could be arranged that &Test.foo has type void
 function(Test) or something.

I would suggest that it should be: function(Test this) with the 'this' being mangled into the name, and affect the calling convention. Structs would be function(ref Test this). And const/shared/immutable decorations should apply properly to the 'this' parameter. I'd wholeheartedly support such an improvement. In fact, I'd be willing to write a DIP on it, if Walter had a chance of approving it. I just don't know if it would happen... -Steve

It needs to be possible to compose delegates: class Foo { void foo () {}; } void delegate () dg; dg.funcptr = &Foo.foo; dg.ptr = cast(void*) new Foo; dg(); At least it needs to be possible to do that in code marked with system. -- /Jacob Carlborg
May 22 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-05-22 20:35, Steven Schveighoffer wrote:

 It needs to be possible to compose delegates:

 class Foo
 {
 void foo () {};
 }

 void delegate () dg;

 dg.funcptr = &Foo.foo;

Error, cannot cast function of type void function(Foo this) to void function(void *this) dg.funcptr = cast(void function(void *this))&Foo.foo; // ok
 dg.ptr = cast(void*) new Foo;
 dg();

 At least it needs to be possible to do that in code marked with  system.

I think it should require a cast, regardless of the system attribute, you are telling the type system a function that requires a Foo is now OK to accept a void *. I don't think that's something we should accept implicitly. -Steve

I have no problem with a couple of case, as long as it's possible to compose delegates as above. The example was just how it works today, and an explanation of what I meant by "composing delegates". This can be of great help when interfacing with other language. I used this technique to call D methods from Objective-C. -- /Jacob Carlborg
May 22 2012
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/22/12 1:14 PM, Steven Schveighoffer wrote:
 I agree, it's unsound. But so is this:

 int *blah = void;

 *blah = 5;

 It doesn't mean that the language should forbid it, or that the compiler
 isn't implemented as designed.

Initialization with void is a feature. My example shows the fail of a feature. There is no comparison.
 At the *very least*, the address to member function operation should be
 illegal in  safe code.

It should be verboten. Other means should be devised for achieving whatever utility is there.
 At best things could be arranged that &Test.foo has type void
 function(Test) or something.

I would suggest that it should be: function(Test this) with the 'this' being mangled into the name, and affect the calling convention. Structs would be function(ref Test this). And const/shared/immutable decorations should apply properly to the 'this' parameter. I'd wholeheartedly support such an improvement. In fact, I'd be willing to write a DIP on it, if Walter had a chance of approving it. I just don't know if it would happen...

Very reasonable. Walter, could you please weigh in on this. Thanks, Andrei
May 22 2012
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/22/12 4:05 PM, Steven Schveighoffer wrote:
 On Tue, 22 May 2012 15:29:10 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 5/22/12 1:14 PM, Steven Schveighoffer wrote:
 I agree, it's unsound. But so is this:

 int *blah = void;

 *blah = 5;

 It doesn't mean that the language should forbid it, or that the compiler
 isn't implemented as designed.

Initialization with void is a feature. My example shows the fail of a feature. There is no comparison.

Your example shows an invalid use for a feature. There are valid uses for that feature that are not unsound.

Typing must always be sound. Andrei
May 22 2012
prev sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Mehrdad" <wfunction hotmail.com> wrote in message 
news:ifswigmcenyryxzyvbpv forum.dlang.org...
 On Friday, 18 May 2012 at 18:59:23 UTC, Steven Schveighoffer wrote:
 On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug. The purpose is so you can get the function pointer portion of a delegate without an instance of the object.

I actually realized that might be the reason before I reported this, but then I thought: In that case, shouldn't the 'this' parameter be explicitly part of the function (at the end of the parameter list)?

No, that won't work in all cases due to the ordering of parameters, 'this' and the hidden struct pointer.
May 18 2012
next sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Mehrdad" <wfunction hotmail.com> wrote in message 
news:sxiwbwuwvcjrlvpfsgpi forum.dlang.org...
 On Saturday, 19 May 2012 at 01:37:54 UTC, Daniel Murphy wrote:
 No, that won't work in all cases due to the ordering of parameters, 
 'this' and the hidden struct pointer.

Better than not working in /any/ cases lol. :P Maybe you can add a void* for the hidden struct parameter? idk...

I'd actually rather it /didn't/ work in any cases, and just returned void*. The .funcptr property of delegates too. From what I can tell the main use of this 'feature' is to cause nasty bugs whenever somebody accidentally takes the address of a non-static member function without an instance. Last time I checked, phobos uses this in a couple of places to see if a member function can be called with a specific set of args, but this can be replaced with S.init.func(...). There is an existing bug report for this somewhere.
May 18 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 19/05/2012 03:37, Daniel Murphy a écrit :
 "Mehrdad"<wfunction hotmail.com>  wrote in message
 news:ifswigmcenyryxzyvbpv forum.dlang.org...
 On Friday, 18 May 2012 at 18:59:23 UTC, Steven Schveighoffer wrote:
 On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org>  wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug. The purpose is so you can get the function pointer portion of a delegate without an instance of the object.

I actually realized that might be the reason before I reported this, but then I thought: In that case, shouldn't the 'this' parameter be explicitly part of the function (at the end of the parameter list)?

No, that won't work in all cases due to the ordering of parameters, 'this' and the hidden struct pointer.

extern(this) and you are done expressing thiscall.
May 19 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 18 May 2012 at 18:30:48 UTC, Andrei Alexandrescu wrote:
 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static. Andrei

Okay I'll report it... hopefully it isn't just with my version though (a little different from official version).
May 18 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 18 May 2012 at 18:32:00 UTC, Mehrdad wrote:
 Okay I'll report it... hopefully it isn't just with my version 
 though (a little different from official version).

http://d.puremagic.com/issues/show_bug.cgi?id=8114
May 18 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug. The purpose is so you can get the function pointer portion of a delegate without an instance of the object. Possible (obscure) usage: class Test { public void foo() { writeln("foo");} public void bar() { writeln("bar");} } void x(Object context, void function() f1, void function() f2) { void delegate() dg; dg.ptr = cast(void *)context; if(uniform(0, 2)) dg.funcptr = f1; else dg.funcptr = f2; dg(); } void main() { auto t = new Test; x(t, &Test.foo, &Test.bar); } Another interesting usage is to test if a function has been overridden: if((&t.foo).funcptr == &Test.foo) writeln("not overridden!"); I personally think the "feature" is too awkward for any real usage. Someone once suggested funcptr and &Test.foo should return void *, so the addresses could be compared, but not used (it's too easy to call this function). In any case, not a bug. -Steve
May 18 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 18 May 2012 at 18:59:23 UTC, Steven Schveighoffer 
wrote:
 On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug. The purpose is so you can get the function pointer portion of a delegate without an instance of the object.

I actually realized that might be the reason before I reported this, but then I thought: In that case, shouldn't the 'this' parameter be explicitly part of the function (at the end of the parameter list)?
May 18 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 18 May 2012 15:17:28 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Friday, 18 May 2012 at 18:59:23 UTC, Steven Schveighoffer wrote:
 On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu  
 <SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug. The purpose is so you can get the function pointer portion of a delegate without an instance of the object.

I actually realized that might be the reason before I reported this, but then I thought: In that case, shouldn't the 'this' parameter be explicitly part of the function (at the end of the parameter list)?

That would be nice, wouldn't it? :) -Steve
May 18 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Saturday, 19 May 2012 at 01:37:54 UTC, Daniel Murphy wrote:
 No, that won't work in all cases due to the ordering of 
 parameters, 'this' and the hidden struct pointer.

Better than not working in /any/ cases lol. :P Maybe you can add a void* for the hidden struct parameter? idk...
May 18 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Saturday, 19 May 2012 at 02:38:11 UTC, Daniel Murphy wrote:
 I'd actually rather it /didn't/ work in any cases, and just 
 returned void*.

Well if that's an option then I like that too.
May 18 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 18 May 2012 16:35:38 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:59 PM, Steven Schveighoffer wrote:
 On Fri, 18 May 2012 14:30:46 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 5/18/12 1:22 PM, Mehrdad wrote:
 My brain just exploded.
 Can someone explain what's going on?

 class Test
 {
 public void foo() { }
 }

 static assert(is(typeof(&Test.foo) == void function()));

Looks like a bug. The assert should pass only if foo were static.

No, this is not a bug.

It is.

Poor design? Yes. Bug? no. It's behavior is very intentional and has been discussed several times over the last several years. It's existed before D2 was even branched, at least since I learned D in 2007.
 The purpose is so you can get the function pointer portion of a delegate
 without an instance of the object.

Typing is what it is. The following program is unsound without a cast in sight: class Test { void foo() { writeln("foo"); } } static assert(is(typeof(&Test.foo) == void function())); void fun() { writeln("fun"); } void main() { alias void function() TFun; TFun a = &fun; a(); a = &Test.foo; a(); }

I agree, it's unsound. But so is this: int *blah = void; *blah = 5; It doesn't mean that the language should forbid it, or that the compiler isn't implemented as designed. At the *very least*, the address to member function operation should be illegal in safe code.
 At best things could be arranged that &Test.foo has type void  
 function(Test) or something.

I would suggest that it should be: function(Test this) with the 'this' being mangled into the name, and affect the calling convention. Structs would be function(ref Test this). And const/shared/immutable decorations should apply properly to the 'this' parameter. I'd wholeheartedly support such an improvement. In fact, I'd be willing to write a DIP on it, if Walter had a chance of approving it. I just don't know if it would happen... -Steve
May 22 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 22 May 2012 14:28:33 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2012-05-22 20:14, Steven Schveighoffer wrote:

 I would suggest that it should be:

 function(Test this) with the 'this' being mangled into the name, and
 affect the calling convention.

 Structs would be function(ref Test this).

 And const/shared/immutable decorations should apply properly to the
 'this' parameter.

 I'd wholeheartedly support such an improvement. In fact, I'd be willing
 to write a DIP on it, if Walter had a chance of approving it. I just
 don't know if it would happen...

It needs to be possible to compose delegates: class Foo { void foo () {}; } void delegate () dg; dg.funcptr = &Foo.foo;

Error, cannot cast function of type void function(Foo this) to void function(void *this) dg.funcptr = cast(void function(void *this))&Foo.foo; // ok
 dg.ptr = cast(void*) new Foo;
 dg();

 At least it needs to be possible to do that in code marked with  system.

I think it should require a cast, regardless of the system attribute, you are telling the type system a function that requires a Foo is now OK to accept a void *. I don't think that's something we should accept implicitly. -Steve
May 22 2012
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 22 May 2012 15:29:10 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 5/22/12 1:14 PM, Steven Schveighoffer wrote:
 I agree, it's unsound. But so is this:

 int *blah = void;

 *blah = 5;

 It doesn't mean that the language should forbid it, or that the compiler
 isn't implemented as designed.

Initialization with void is a feature. My example shows the fail of a feature. There is no comparison.

Your example shows an invalid use for a feature. There are valid uses for that feature that are not unsound. But I think we are on the same page -- the misfeature is not that you *can* take a member address, it's the *type* that it is given.
 At the *very least*, the address to member function operation should be
 illegal in  safe code.

It should be verboten. Other means should be devised for achieving whatever utility is there.

I agree, the feature is prone to error. -Steve
May 22 2012