www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Conversion of delegate with default arguments to delegate with less

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Code:

void main()
{
    auto foo = (int x = 10){ /* */ };
    void delegate() bar = foo;
}

Since foo takes an argument that already has a default it can be used
as a simple `void delegate()`, so maybe it makes sense for `foo` to be
able to implicitly convert to such a type.

Unfortunately doing a cast doesn't work properly:

import std.stdio;

void main()
{
    auto foo = (int x = 10){ writeln(x); };
    void delegate() bar;
    bar = cast(typeof(bar))foo;

    bar();  // prints garbage
}

So maybe this type of conversion is impossible in the first place due
to how arguments are passed? I don't know all the technical tidbits,
but from a user's point of view an implicit conversion kind of makes
sense (if it's possible).
Sep 02 2011
next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Fri, 02 Sep 2011 22:11:50 +0300, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 So maybe this type of conversion is impossible in the first place due
 to how arguments are passed?

Yes. The default value is pushed on the stack at the call site.
  I don't know all the technical tidbits,
 but from a user's point of view an implicit conversion kind of makes
 sense (if it's possible).

The compiler would need to generate a function to do the conversion. I think the same could be achieved with a template. -- Best regards, Vladimir mailto:vladimir thecybershadow.net
Sep 02 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/02/2011 11:49 PM, Andrej Mitrovic wrote:
 On 9/2/11, Vladimir Panteleev<vladimir thecybershadow.net>  wrote:
 On Fri, 02 Sep 2011 22:11:50 +0300, Andrej Mitrovic
 <andrej.mitrovich gmail.com>  wrote:

 So maybe this type of conversion is impossible in the first place due
 to how arguments are passed?

Yes. The default value is pushed on the stack at the call site.

Yeah, I should have thought more before I posted. The default value is not "tied" to the function, the values are inserted by the compiler at the call site, doh. :)

The solution is this: void main() { auto foo = (int x = 10){ /* */ } void delegate() bar = { return foo(); } } the compiler could in theory just automatically insert a thunk like this. Related: I think that function pointers should implicitly decay to delegates. This would allow the compiler to optimize some delegate literals to function pointers if they don't access the outer scope, without breaking any code that wants to use such a function literal as a delegate.
Sep 02 2011
next sibling parent reply travert phare.normalesup.org (Christophe) writes:
 void main()
 {
      auto foo = (int x = 10){ /* */ }
      void delegate() bar = { return foo(); }
 }
 
 the compiler could in theory just automatically insert a thunk like 
 this.

That sounds reasonable.
Sep 03 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/03/2011 03:12 PM, Martin Nowak wrote:
 On Sat, 03 Sep 2011 11:50:25 +0200, Christophe
 <travert phare.normalesup.org> wrote:

 void main()
 {
 auto foo = (int x = 10){ /* */ }
 void delegate() bar = { return foo(); }
 }

 the compiler could in theory just automatically insert a thunk like
 this.

That sounds reasonable.

This look like a library solution would be best. I suppose you want to store a homogeneous list of delegates. Actually std.bind should do exactly this, but the module is broken and needs a rewrite. You should also be able to use std.functional's curry but it turns out it's implementation can't handle anything but two parameter functions. I'll make a pull request for this one though. Then you should be able to do 'alias curry!(foo, 10) bar'

http://d.puremagic.com/issues/show_bug.cgi?id=4391 Make sure to call the new implementation 'partial' or similar.
Sep 03 2011
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/2/11 9:52 PM, Andrej Mitrovic wrote:
 On 9/3/11, Timon Gehr<timon.gehr gmx.ch>  wrote:
 Related: I think that function pointers should implicitly decay to
 delegates. This would allow the compiler to optimize some delegate
 literals to function pointers if they don't access the outer scope,
 without breaking any code that wants to use such a function literal as a
 delegate.

Well in TDPL it says that function literals are function literals by default unless the compiler determines they must be delegates. But currently all function literals are delegates unless explicitly marked with 'function'.

Yah, Walter explicitly approved that paragraph but didn't get around to implementing it. Andrei
Sep 03 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/2/11, Vladimir Panteleev <vladimir thecybershadow.net> wrote:
 On Fri, 02 Sep 2011 22:11:50 +0300, Andrej Mitrovic
 <andrej.mitrovich gmail.com> wrote:

 So maybe this type of conversion is impossible in the first place due
 to how arguments are passed?

Yes. The default value is pushed on the stack at the call site.

Yeah, I should have thought more before I posted. The default value is not "tied" to the function, the values are inserted by the compiler at the call site, doh. :)
Sep 02 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/3/11, Timon Gehr <timon.gehr gmx.ch> wrote:
 Related: I think that function pointers should implicitly decay to
 delegates. This would allow the compiler to optimize some delegate
 literals to function pointers if they don't access the outer scope,
 without breaking any code that wants to use such a function literal as a
 delegate.

Well in TDPL it says that function literals are function literals by default unless the compiler determines they must be delegates. But currently all function literals are delegates unless explicitly marked with 'function'.
Sep 02 2011
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-09-02 21:11, Andrej Mitrovic wrote:
 Code:

 void main()
 {
      auto foo = (int x = 10){ /* */ };
      void delegate() bar = foo;
 }

 Since foo takes an argument that already has a default it can be used
 as a simple `void delegate()`, so maybe it makes sense for `foo` to be
 able to implicitly convert to such a type.

 Unfortunately doing a cast doesn't work properly:

 import std.stdio;

 void main()
 {
      auto foo = (int x = 10){ writeln(x); };
      void delegate() bar;
      bar = cast(typeof(bar))foo;

      bar();  // prints garbage
 }

 So maybe this type of conversion is impossible in the first place due
 to how arguments are passed? I don't know all the technical tidbits,
 but from a user's point of view an implicit conversion kind of makes
 sense (if it's possible).

I think it would be usable. I also think that a delegate/function that returns a value could be implicitly converted to a delegate/function of the same signature but returns void instead. I would be the same as calling the delegate that returns a value and not assign the returned value to a variable. -- /Jacob Carlborg
Sep 03 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/03/2011 11:34 AM, Jacob Carlborg wrote:
 On 2011-09-02 21:11, Andrej Mitrovic wrote:
 Code:

 void main()
 {
 auto foo = (int x = 10){ /* */ };
 void delegate() bar = foo;
 }

 Since foo takes an argument that already has a default it can be used
 as a simple `void delegate()`, so maybe it makes sense for `foo` to be
 able to implicitly convert to such a type.

 Unfortunately doing a cast doesn't work properly:

 import std.stdio;

 void main()
 {
 auto foo = (int x = 10){ writeln(x); };
 void delegate() bar;
 bar = cast(typeof(bar))foo;

 bar(); // prints garbage
 }

 So maybe this type of conversion is impossible in the first place due
 to how arguments are passed? I don't know all the technical tidbits,
 but from a user's point of view an implicit conversion kind of makes
 sense (if it's possible).

I think it would be usable. I also think that a delegate/function that returns a value could be implicitly converted to a delegate/function of the same signature but returns void instead. I would be the same as calling the delegate that returns a value and not assign the returned value to a variable.

Note that this would also require a thunk that explicitly discards the result value in non-trivial cases.
Sep 03 2011
prev sibling next sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
On Sat, 03 Sep 2011 11:50:25 +0200, Christophe  
<travert phare.normalesup.org> wrote:

 void main()
 {
      auto foo = (int x = 10){ /* */ }
       void delegate() bar = { return foo(); }
 }

 the compiler could in theory just automatically insert a thunk like
  this.

That sounds reasonable.

This look like a library solution would be best. I suppose you want to store a homogeneous list of delegates. Actually std.bind should do exactly this, but the module is broken and needs a rewrite. You should also be able to use std.functional's curry but it turns out it's implementation can't handle anything but two parameter functions. I'll make a pull request for this one though. Then you should be able to do 'alias curry!(foo, 10) bar' martin
Sep 03 2011
prev sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
On Sat, 03 Sep 2011 23:03:18 +0200, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 09/03/2011 03:12 PM, Martin Nowak wrote:
 On Sat, 03 Sep 2011 11:50:25 +0200, Christophe
 <travert phare.normalesup.org> wrote:

 void main()
 {
 auto foo = (int x = 10){ /* */ }
 void delegate() bar = { return foo(); }
 }

 the compiler could in theory just automatically insert a thunk like
 this.

That sounds reasonable.

This look like a library solution would be best. I suppose you want to store a homogeneous list of delegates. Actually std.bind should do exactly this, but the module is broken and needs a rewrite. You should also be able to use std.functional's curry but it turns out it's implementation can't handle anything but two parameter functions. I'll make a pull request for this one though. Then you should be able to do 'alias curry!(foo, 10) bar'

http://d.puremagic.com/issues/show_bug.cgi?id=4391 Make sure to call the new implementation 'partial' or similar.

Sounds reasonable, but someone should write an implementation of 'curry' then. Besides does anybody know how to get 'deprecated alias old new' to actually bark? martin
Sep 03 2011