www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Address of parameterless ref function

reply Timon Gehr <timon.gehr gmx.ch> writes:
Whats the output of the following code supposed to be?

import std.stdio;

int a=0;
ref int g(){
    writeln("called g");
    return ++a;
}

void main(){
    int function() f=&g;
    writeln(cast(int)&a);
    writeln(f());
    writeln(f());
    writeln(f());
}

The output using dmd 2.052
-144918776
called g
-144918776
called g
-144918776
called g
-144918776

This is certainly wrong, as it includes an IMPLICIT cast from int* to int, but
there are happening other strange things.

How to distinguish taking the address of a call to a parameterless ref
function from taking the address of the function itself anyways?
Apr 09 2011
next sibling parent Cliff Hudson <cliff.s.hudson gmail.com> writes:
It looks like in the absence of an assignment of the output of g() to some
value (say int b = g()) which the compiler would insert conversion code for,
the ref is retaining some pointer semantics.  I'm guessing that because
writeln is variadic the compiler doesn't do anything with g's output (like
dereference it, convert it to an int, etc.), so you just keep getting the
pointer of 'a' back.  I don't know the internals, but I'm guessing ref is
syntactic sugar to make pointer operations appear like normal value
operations.  If you replaced (conceptually) ref int g() with int* g(), and
replace return ++a with ++a; return &a, then you'd get the output you see.

- Cliff

On Sat, Apr 9, 2011 at 9:59 AM, Timon Gehr <timon.gehr gmx.ch> wrote:

 Whats the output of the following code supposed to be?

 import std.stdio;

 int a=0;
 ref int g(){
    writeln("called g");
    return ++a;
 }

 void main(){
    int function() f=&g;
    writeln(cast(int)&a);
    writeln(f());
    writeln(f());
    writeln(f());
 }

 The output using dmd 2.052
 -144918776
 called g
 -144918776
 called g
 -144918776
 called g
 -144918776

 This is certainly wrong, as it includes an IMPLICIT cast from int* to int,
 but
 there are happening other strange things.

 How to distinguish taking the address of a call to a parameterless ref
 function from taking the address of the function itself anyways?
Apr 09 2011
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Interesting. The problem I think is that the delegate is declared as
returning int, not ref int. I don't even think we can specify ref as
the return value of a delegate. But if you try to declare the delegate
as returning an int*, you get this nice error:

Error: cannot implicitly convert expression (& g) of type int
function() ref to int* function()

Still, you can't declare the delegate as "int function() ref" or "ref
int function()". I'm not sure why, or why int* can be implicitly cast
to int in this case.
Apr 09 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
I think I get it now. The example is actually invalid code accepted by the dmd
frontend. It allows a pointer of type "int function() ref" to be implicitly
converted to "int function()". Internally the "int function() ref" returns a
pointer to an integer. Both integers and pointers are returned the same way (EAX
register AFAIK). Therefore, after the assignment f=&g, the function f=&g is
treated as if it was a function that returns an int in the EAX register, while
actually it returns a reference to an int in the EAX register. The EAX contents
of
the EAX register are just interpreted differently. That is how the implicit
reinterpret-cast from "int ref" to "int" takes place.

I am filing a bug report.

BTW: You can actually declare a variable of type "int function() ref" by the
means
of the auto keyword, but not in any other way. I assume this is a bug too.
Apr 10 2011
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
You can also use this:
typeof(&g) f;
f = &g;

But I'd say it's definitely a bug if we can't declare delegates with
ref returns.
Apr 10 2011
prev sibling next sibling parent Cliff Hudson <cliff.s.hudson gmail.com> writes:
Which compiler are you using?  Have you tried a different one?

On Sat, Apr 9, 2011 at 10:55 AM, Andrej Mitrovic <andrej.mitrovich gmail.com
 wrote:
 Interesting. The problem I think is that the delegate is declared as
 returning int, not ref int. I don't even think we can specify ref as
 the return value of a delegate. But if you try to declare the delegate
 as returning an int*, you get this nice error:

 Error: cannot implicitly convert expression (& g) of type int
 function() ref to int* function()

 Still, you can't declare the delegate as "int function() ref" or "ref
 int function()". I'm not sure why, or why int* can be implicitly cast
 to int in this case.
Apr 09 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I'm using DMD 2.052. Why, are you allowed to declare delegates with ref returns?
Apr 09 2011
prev sibling next sibling parent Cliff Hudson <cliff.s.hudson gmail.com> writes:
No I was wondering if a different compiler would treat the assignment of &g
to f as needing to generate a conversion from int* to int internally (which
I think is what Timon was expecting?), or if it would generate an error
because the signature of f does not match the signature of g (which is what
I would expect.)

On Sat, Apr 9, 2011 at 11:12 AM, Andrej Mitrovic <andrej.mitrovich gmail.com
 wrote:
 I'm using DMD 2.052. Why, are you allowed to declare delegates with ref
 returns?
Apr 09 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
It's the same with GDC as is with DMD, just checked.
Apr 09 2011