Jump to page: 1 2
Thread overview
Cannot implicitly convert delegate to function
Apr 27, 2006
Lionello Lunesu
Apr 27, 2006
Lionello Lunesu
Apr 27, 2006
BCS
Apr 27, 2006
Lionello Lunesu
Apr 28, 2006
Don Clugston
Apr 28, 2006
Lionello Lunesu
Apr 27, 2006
Stewart Gordon
Apr 27, 2006
Thomas Kuehne
Apr 28, 2006
Lionello Lunesu
May 01, 2006
Bruno Medeiros
May 01, 2006
BCS
Apr 27, 2006
pragma
Apr 30, 2006
Bruno Medeiros
Apr 27, 2006
Lionello Lunesu
Re: Cannot implicitly convert FUNCTION to DELEGATE
Apr 28, 2006
Lionello Lunesu
April 27, 2006
Hi,

Shouldn't a (pointer to a) function be convertible to a delegate? Seems to me it's like casting an int to a long; the latter has "more info" and can be converted back into the former without the loss of data. The same holds for function/delegate: a function could be converted to a delegate for "null"; by forgetting the "this" (null), we get the function pointer back.

#import std.format;
#void _disp_putc( dchar c ) {
#	int i = cast(int)c;
#	if (c >= 0x80)
#		i = '?';
#//	disp_putc(i);
#}
#void disp_writef(...) {
#	std.format.doFormat(&_disp_putc,_arguments,_argptr);
#}

Results in (v0.154):

>dmd t.d
t.d(9): function std.format.doFormat (void delegate(dchar),TypeInfo[],void*) does not match argument types (void(*)(dchar c),TypeInfo[],void*)
t.d(9): cannot implicitly convert expression (& _disp_putc) of type void(*)(dchar c) to void delegate(dchar)


Right?

L.
April 27, 2006
(Yes, obviously I could put the function inside a class, but that's just adding overhead that shouldn't be necessary in the first place)
April 27, 2006
"Lionello Lunesu" <lio@lunesu.remove.com> wrote in message news:e2qig4$1ovk$1@digitaldaemon.com...
> Hi,
>
> Shouldn't a (pointer to a) function be convertible to a delegate? Seems to me it's like casting an int to a long; the latter has "more info" and can be converted back into the former without the loss of data. The same holds for function/delegate: a function could be converted to a delegate for "null"; by forgetting the "this" (null), we get the function pointer back.

Without the context pointer, a delegate cannot function properly.  So casting from delegate to function isn't really possible.

The other way around.. I don't think so either.  Something tells me the mechanism for a delegate call would screw up if the context pointer were null, or if the function weren't designed to be a delegate.


April 27, 2006
In article <e2qlrk$1uh5$1@digitaldaemon.com>, Jarrett Billingsley says...
>
>"Lionello Lunesu" <lio@lunesu.remove.com> wrote in message news:e2qig4$1ovk$1@digitaldaemon.com...
>> Hi,
>>
>> Shouldn't a (pointer to a) function be convertible to a delegate? Seems to me it's like casting an int to a long; the latter has "more info" and can be converted back into the former without the loss of data. The same holds for function/delegate: a function could be converted to a delegate for "null"; by forgetting the "this" (null), we get the function pointer back.
>
>Without the context pointer, a delegate cannot function properly.  So casting from delegate to function isn't really possible.
>
>The other way around.. I don't think so either.  Something tells me the mechanism for a delegate call would screw up if the context pointer were null, or if the function weren't designed to be a delegate.
>
>

It would take some ASM hacking but It might be possible to place the fn ptr in the context pointer and have the delegate's function rearrange the stack and then call (with tail recursion) the function.


April 27, 2006
Jarrett Billingsley wrote:
<snip>
> The other way around.. I don't think so either.  Something tells me the mechanism for a delegate call would screw up if the context pointer were null, or if the function weren't designed to be a delegate. 

But why?  I can't understand why a function that doesn't touch the context pointer at all can't be trivially be converted to a delegate in which the context pointer is null.

Stewart.
April 27, 2006
Jarrett Billingsley wrote:
> "Lionello Lunesu" <lio@lunesu.remove.com> wrote in message news:e2qig4$1ovk$1@digitaldaemon.com...
>> Hi,
>>
>> Shouldn't a (pointer to a) function be convertible to a delegate? Seems to me it's like casting an int to a long; the latter has "more info" and can be converted back into the former without the loss of data. The same holds for function/delegate: a function could be converted to a delegate for "null"; by forgetting the "this" (null), we get the function pointer back.
> 
> Without the context pointer, a delegate cannot function properly.  So casting from delegate to function isn't really possible.


I meant it the int-long way: you can cast an int to a long and back without loss of data.

L.
April 27, 2006
BCS wrote:
> In article <e2qlrk$1uh5$1@digitaldaemon.com>, Jarrett Billingsley says...
>> "Lionello Lunesu" <lio@lunesu.remove.com> wrote in message news:e2qig4$1ovk$1@digitaldaemon.com...
>>> Hi,
>>>
>>> Shouldn't a (pointer to a) function be convertible to a delegate? Seems to me it's like casting an int to a long; the latter has "more info" and can be converted back into the former without the loss of data. The same holds for function/delegate: a function could be converted to a delegate for "null"; by forgetting the "this" (null), we get the function pointer back.
>> Without the context pointer, a delegate cannot function properly.  So casting from delegate to function isn't really possible.
>>
>> The other way around.. I don't think so either.  Something tells me the mechanism for a delegate call would screw up if the context pointer were null, or if the function weren't designed to be a delegate. 
>>
>>
> 
> It would take some ASM hacking but It might be possible to place the fn ptr in
> the context pointer and have the delegate's function rearrange the stack and
> then call (with tail recursion) the function.

Isn't "this" basically a hidden parameter? A delegate would be a "this" together with a function pointer. Upon calling it would first load/push the hidden parameter before the call to the function.

The question then is: does "this" interfere with a function's parameter?

If, like in the MSVC case, "this" is always loaded into register ecx, it would just work: ecx would get "null" and the function gets called with the usual parameters. Since the function does not access [ecx] (it's a function, not a member of any class) the null would not interfere.

L.
April 27, 2006
Lionello Lunesu wrote:
> (Yes, obviously I could put the function inside a class, but that's just adding overhead that shouldn't be necessary in the first place)

Could always wrap it in an anonymous delegate:
#import std.format;
#void _disp_putc( dchar c ) {
#    int i = cast(int)c;
#    if (c >= 0x80)
#        i = '?';
#//    disp_putc(i);
#}
#void disp_writef(...) {
#    std.format.doFormat(delegate void(dchar c){_disp_putc(c);},_arguments,_argptr);
#}

But still, for something this trivial its just overkill.  I do believe I recall Walter saying that, at some unknown future point, he intends function pointers and delegates to merge into a single type, but I don't know what the precise plan of action (if any) might be to that end.  It would certainly help solve soft spots like this one, though.

-- Chris Nicholson-Sauls
April 27, 2006
Stewart Gordon schrieb am 2006-04-27:
> Jarrett Billingsley wrote:
><snip>
>> The other way around.. I don't think so either.  Something tells me the mechanism for a delegate call would screw up if the context pointer were null, or if the function weren't designed to be a delegate.
>
> But why?  I can't understand why a function that doesn't touch the context pointer at all can't be trivially be converted to a delegate in which the context pointer is null.

Let's try it:

# class C{
#     void foo(){
#         printf("foo\n");
#     }
#
#     static void bar(){
#         printf("bar\n");
#     }
# }
#
# int main(){
#     C c = new C();
#
#     void delegate() d = &c.foo;
#     void* p = cast(void*)&d;
#     int* i = cast(int*) p;
#
#     printf("delegate:\n");
#     printf("%08X (instance)\n", c);
#     printf("%08X %08X (raw delegate)\n", i[0], i[1]);
#     d();
#
#     printf("\nfunction:\n");
#     void function() f = &C.bar;
#     p = cast(void*)&f;
#     int* j = cast(int*) p;
#     printf("%08X (function)\n", &C.bar);
#     printf("%08X (raw function)\n", j[0]);
#     f();
#
#     printf("\nfunction -> instance delegate\n");
#     i[1] = j[0];
#     printf("%08X (instance)\n", c);
#     printf("%08X %08X (raw delegate)\n", i[0], i[1]);
#     d();
#
#     printf("\nfunction -> null delegate\n");
#     i[0] = 0;
#     printf("%08X %08X (raw delegate)\n", i[0], i[1]);
#     d();
#
#     return 0;
# }


delegate:
55719FE0 (instance)
55719FE0 08049DF4 (raw delegate)
foo

function:
08049E0C (function)
08049E0C (raw function)
bar

function -> instance delegate
55719FE0 (instance)
55719FE0 08049E0C (raw delegate)
bar

function -> null delegate
00000000 08049E0C (raw delegate)
bar

I don't see any problems - except for missing compiler support.

Thomas


April 27, 2006
In article <e2qv42$2gnt$1@digitaldaemon.com>, Stewart Gordon says...
>
>Jarrett Billingsley wrote:
><snip>
>> The other way around.. I don't think so either.  Something tells me the mechanism for a delegate call would screw up if the context pointer were null, or if the function weren't designed to be a delegate.
>
>But why?  I can't understand why a function that doesn't touch the context pointer at all can't be trivially be converted to a delegate in which the context pointer is null.
>

Well, there's always the trival solution of declaring all of your "functions" as static members of a class - but that's not always possible. ;)

Direct conversion can be done, but would require DMD to inject a good deal of code to replace an otherwise simple cast.

For example, given the following:

/**/ alias uint function(uint foo,uint bar) FunctionType;
/**/ alias uint function(uint foo,uint bar) Delegatetype;
/**/ FunctionType fn = &myfunc;

An explicit cast from function to delegate is processed:

/**/ Delegatetype dg = cast(DelegateType)&fn;

In response to a function-to-delegate cast, with matching signatures, DMD would emit code equivalent to this:

/**/ class FunctionTypeDelegate{
/**/     FunctionType fn;
/**/     public this(FunctionType fn){ this.fn = fn; }
/**/     uint dg(uint foo,uint bar){ return fn(foo,bar); }
/**/ }
/**/ DelegateType dg = &((new FunctionTypeDelegate(&fn)).dg);

Using a proxy class/object in this way presents a side-effect-free way to tackle the problem.  It's also friendly to different calling conventions, as well as going from one convention to another (the concept could even be useful for function-to-function and delegate-to-delegate where conventions don't match).

DMD could simply generate the "FunctionTypeDelegate" class and provide it in the same manner as it would a template (in a COMDAT OMF record).  This way, it won't cause issues if a cast elsewhere generates the same exact proxy.

Now, this *could* be implemented via a template, barring some limitations. However, it would take some rather serious hacking to accomplish with the same kind of simplicity as a cast(), when you could probably hand-code the proxy above with far less effort (we're talking hours versus seconds, for the first time around).

$0.02:
Another way to look at it: any one type of delegate is compatible with exactly
one type of function.  So having the compiler interpret a cast() really doesn't
gain you all that much.  You may as well write a proxy for each delegate in
cases where you absolutely have to be compatible with free-functions.  Also,
using proxies is the only way to accept multiple types of delegates in an
abstract way, so it then becomes a matter of using just one convention for
simplicity's sake.

- EricAnderton at yahoo
« First   ‹ Prev
1 2