www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Address of overloaded functions

reply "John Colvin" <john.loughran.colvin gmail.com> writes:
Is there any way to take the address of any of an overloaded set 
of functions?

import std.stdio;

void foo(int a){ writeln("overload int"); }
void foo(long b){ writeln("overload long"); }

void main()
{
     auto b = &foo; //ambiguous => error
     b(2); //valid for either overload
}
Jul 03 2013
next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 07/03/13 16:52, John Colvin wrote:
 Is there any way to take the address of any of an overloaded set of functions?
 
 import std.stdio;
 
 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }
 
 void main()
 {
     auto b = &foo; //ambiguous => error
     b(2); //valid for either overload
 }
void function(long) b = &foo; artur
Jul 03 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Wednesday, 3 July 2013 at 15:03:46 UTC, Artur Skawina wrote:
 On 07/03/13 16:52, John Colvin wrote:
 Is there any way to take the address of any of an overloaded 
 set of functions?
 
 import std.stdio;
 
 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }
 
 void main()
 {
     auto b = &foo; //ambiguous => error
     b(2); //valid for either overload
 }
void function(long) b = &foo; artur
Thanks, that works
Jul 03 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jul 03, 2013 at 05:15:48PM +0200, John Colvin wrote:
 On Wednesday, 3 July 2013 at 15:03:46 UTC, Artur Skawina wrote:
On 07/03/13 16:52, John Colvin wrote:
Is there any way to take the address of any of an overloaded set
of functions?

import std.stdio;

void foo(int a){ writeln("overload int"); }
void foo(long b){ writeln("overload long"); }

void main()
{
    auto b = &foo; //ambiguous => error
    b(2); //valid for either overload
}
void function(long) b = &foo; artur
Thanks, that works
This is interesting. How does C++ handle this? (Or does it?) T -- Debian GNU/Linux: Cray on your desktop.
Jul 03 2013
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/03/13 17:27, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 05:15:48PM +0200, John Colvin wrote:
 On Wednesday, 3 July 2013 at 15:03:46 UTC, Artur Skawina wrote:
 On 07/03/13 16:52, John Colvin wrote:
 Is there any way to take the address of any of an overloaded set
 of functions?

 import std.stdio;

 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }

 void main()
 {
    auto b = &foo; //ambiguous => error
    b(2); //valid for either overload
 }
void function(long) b = &foo; artur
Thanks, that works
This is interesting. How does C++ handle this? (Or does it?)
The same - the context determines which overload is chosen, and ambiguity is an error. artur
Jul 03 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jul 03, 2013 at 05:41:25PM +0200, Artur Skawina wrote:
 On 07/03/13 17:27, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 05:15:48PM +0200, John Colvin wrote:
 On Wednesday, 3 July 2013 at 15:03:46 UTC, Artur Skawina wrote:
 On 07/03/13 16:52, John Colvin wrote:
 Is there any way to take the address of any of an overloaded set
 of functions?

 import std.stdio;

 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }

 void main()
 {
    auto b = &foo; //ambiguous => error
    b(2); //valid for either overload
 }
void function(long) b = &foo; artur
Thanks, that works
This is interesting. How does C++ handle this? (Or does it?)
The same - the context determines which overload is chosen, and ambiguity is an error.
Oh, so it tells the difference by whether you write void (*p)(int) = foo; or void (*p)(long) = foo; ? I guess that makes sense. T -- There are 10 kinds of people in the world: those who can count in binary, and those who can't.
Jul 03 2013
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/03/13 17:43, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 05:41:25PM +0200, Artur Skawina wrote:
 On 07/03/13 17:27, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 05:15:48PM +0200, John Colvin wrote:
 On Wednesday, 3 July 2013 at 15:03:46 UTC, Artur Skawina wrote:
 On 07/03/13 16:52, John Colvin wrote:
 Is there any way to take the address of any of an overloaded set
 of functions?

 import std.stdio;

 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }

 void main()
 {
    auto b = &foo; //ambiguous => error
    b(2); //valid for either overload
 }
void function(long) b = &foo; artur
Thanks, that works
This is interesting. How does C++ handle this? (Or does it?)
The same - the context determines which overload is chosen, and ambiguity is an error.
Oh, so it tells the difference by whether you write void (*p)(int) = foo; or void (*p)(long) = foo; ?
Yep. Things like void c(void (*fp)(long), long a) { fp(a); } c(foo, 2); work as expected too.
 I guess that makes sense.
The context dependence isn't ideal, but what's the alternative?... artur
Jul 03 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jul 03, 2013 at 06:07:07PM +0200, Artur Skawina wrote:
 On 07/03/13 17:43, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 05:41:25PM +0200, Artur Skawina wrote:
 On 07/03/13 17:27, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 05:15:48PM +0200, John Colvin wrote:
 On Wednesday, 3 July 2013 at 15:03:46 UTC, Artur Skawina wrote:
 On 07/03/13 16:52, John Colvin wrote:
 Is there any way to take the address of any of an overloaded set
 of functions?

 import std.stdio;

 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }

 void main()
 {
    auto b = &foo; //ambiguous => error
    b(2); //valid for either overload
 }
void function(long) b = &foo; artur
Thanks, that works
This is interesting. How does C++ handle this? (Or does it?)
The same - the context determines which overload is chosen, and ambiguity is an error.
Oh, so it tells the difference by whether you write void (*p)(int) = foo; or void (*p)(long) = foo; ?
Yep. Things like void c(void (*fp)(long), long a) { fp(a); } c(foo, 2); work as expected too.
 I guess that makes sense.
The context dependence isn't ideal, but what's the alternative?...
[...] Explicit syntax for specifying overloads? ;-) Not like that would happen in D, though. T -- Error: Keyboard not attached. Press F1 to continue. -- Yoon Ha Lee, CONLANG
Jul 03 2013
prev sibling next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 07/03/13 18:24, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 06:07:07PM +0200, Artur Skawina wrote:
 The context dependence isn't ideal, but what's the alternative?...
[...] Explicit syntax for specifying overloads? ;-) Not like that would happen in D, though.
Real Programmers need no special syntax :) import std.stdio; void foo(int a){ writeln("overload int"); } void foo(long b){ writeln("overload long"); } auto pickOverload(alias FP, A...)() property { typeof(FP(A.init)) function(A) fp = &FP; return fp;} void main() { auto b = pickOverload!(foo, long); b(2); } But using the context to automatically figure out the right overload make some things easier; it's just that eg the lhs of an assignment affecting the result of the rhs-expression doesn't /feel/ right. artur
Jul 03 2013
parent reply "Tyro[17]" <ridimz yahoo.com> writes:
On 7/3/13 12:52 PM, Artur Skawina wrote:
 import std.stdio;

     void foo(int a){ writeln("overload int"); }
     void foo(long b){ writeln("overload long"); }

     auto pickOverload(alias FP, A...)()  property { typeof(FP(A.init))
function(A) fp = &FP; return fp;}

     void main()
     {
         auto b = pickOverload!(foo, long);
         b(2);
     }
Often I see terse demonstrations of ingenious ways of doing things in the language but am at a lost as with regards to under what circumstances on would use such a feature. This happens to be one of those cases. Could you provide a couple circumstances where this would prove useful/handy? Thanks, -- Andrew Edwards -------------------- http://www.akeron.co auto getAddress() { string location = " ", period = "."; return ("info" ~ location ~ "afidem" ~ period ~ "org"); }
Jul 03 2013
parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/04/13 01:31, Tyro[17] wrote:
 On 7/3/13 12:52 PM, Artur Skawina wrote:
 import std.stdio;

     void foo(int a){ writeln("overload int"); }
     void foo(long b){ writeln("overload long"); }

     auto pickOverload(alias FP, A...)()  property { typeof(FP(A.init))
function(A) fp = &FP; return fp;}

     void main()
     {
         auto b = pickOverload!(foo, long);
         b(2);
     }
Often I see terse demonstrations of ingenious ways of doing things in the language but am at a lost as with regards to under what circumstances on would use such a feature. This happens to be one of those cases. Could you provide a couple circumstances where this would prove useful/handy?
Any time you need a pointer to an overloaded symbol - it's not possible to simply take its address, because there isn't enough information to tell which function you're interested in. Overload resolution happens at the call site (by matching the argument list); if you're not calling the function you need another mechanism to disambiguate. When taking an address of an overloaded function C++ (and D) selects the right one by looking at the context, ie the "target". But that means that you need to know the exact signature of the function - which isn't necessarily the case, especially with D's auto and templates. For example, you may not care what the return type is; in D a type name can easily be longer than a page, or require `typeof()`, so it can also be hard if not impossible to write down. "pickOverload" lets you ignore all the uninteresting details - the compiler already knows them - you only have specify the arguments you intend to call the function pointer with. Actually, while context alone is mostly enough for std-C++-w/o-extensions, it's not really enough for D - eg the above pickOverload implementation will lose the function attributes and linkage. Which is a much bigger problem in D because " safe" etc are often inferred. It's unreasonable to require the type of the "b" variable to always be up-to-date, when foo's signature can be changing relatively often, or even be unpredictable, like when the code is inside a template. So a better pickOverload implementation would be: template ID(T...) { alias T ID; } template getOverloads(alias F) { alias getOverloads = ID!(__traits(getOverloads, __traits(parent, F), __traits(identifier, F))); } auto pickOverload(alias F, A...)() property { static if (__traits(compiles, function(){typeof(F(A.init)) function(A) fp = &F;})) enum typeof(F(A.init)) function(A) fp = &F; else static if (__traits(compiles, function(){extern (C) typeof(F(A.init)) function(A) fp = &F;})) extern (C) enum typeof(F(A.init)) function(A) fp = &F; foreach (O; getOverloads!F) static if (is(typeof(&O==fp))) if (&O==fp) return &O; assert(0); } This now no longer loses information and works with safe/pure etc code. But it's anything but obvious, and extending it to handle other calling conventions wouldn't scale. Hence a trait that does the overload resolution and returns the chosen one would be a better idea. artur
Jul 04 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jul 03, 2013 at 06:52:56PM +0200, Artur Skawina wrote:
 On 07/03/13 18:24, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 06:07:07PM +0200, Artur Skawina wrote:
 The context dependence isn't ideal, but what's the alternative?...
[...] Explicit syntax for specifying overloads? ;-) Not like that would happen in D, though.
Real Programmers need no special syntax :) import std.stdio; void foo(int a){ writeln("overload int"); } void foo(long b){ writeln("overload long"); } auto pickOverload(alias FP, A...)() property { typeof(FP(A.init)) function(A) fp = &FP; return fp;}
Wow. I didn't know you could use A.init for variadic A... ! That's amazing. D rawkz!!
    void main()
    {
        auto b = pickOverload!(foo, long);
Now *that's* what I call coolness. Self-documenting and convenient to use (though in this case it's arguable whether it's actually better than native syntax).
        b(2);
    }
[...] T -- What doesn't kill me makes me stranger.
Jul 03 2013
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/03/13 21:02, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 06:52:56PM +0200, Artur Skawina wrote:
    void main()
    {
        auto b = pickOverload!(foo, long);
Now *that's* what I call coolness. Self-documenting and convenient to use (though in this case it's arguable whether it's actually better than native syntax).
At some point somebody is going to ask for auto b = foo.pickOverload!(long) with a better name for 'pickOverload'. :) Which actually is possible, but would need sane optional-() and UFCS models. Ie not right now. artur
Jul 03 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jul 03, 2013 at 10:10:08PM +0200, Artur Skawina wrote:
 On 07/03/13 21:02, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 06:52:56PM +0200, Artur Skawina wrote:
    void main()
    {
        auto b = pickOverload!(foo, long);
Now *that's* what I call coolness. Self-documenting and convenient to use (though in this case it's arguable whether it's actually better than native syntax).
At some point somebody is going to ask for auto b = foo.pickOverload!(long) with a better name for 'pickOverload'. :) Which actually is possible, but would need sane optional-() and UFCS models. Ie not right now.
[...] I don't think UFCS applies to compile-time arguments? So this wouldn't work. T -- There's light at the end of the tunnel. It's the oncoming train.
Jul 03 2013
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/03/13 22:44, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 10:10:08PM +0200, Artur Skawina wrote:
 On 07/03/13 21:02, H. S. Teoh wrote:
 On Wed, Jul 03, 2013 at 06:52:56PM +0200, Artur Skawina wrote:
    void main()
    {
        auto b = pickOverload!(foo, long);
Now *that's* what I call coolness. Self-documenting and convenient to use (though in this case it's arguable whether it's actually better than native syntax).
At some point somebody is going to ask for auto b = foo.pickOverload!(long) with a better name for 'pickOverload'. :) Which actually is possible, but would need sane optional-() and UFCS models. Ie not right now.
[...] I don't think UFCS applies to compile-time arguments? So this wouldn't work.
Like i said - not right now. Extending UFCS to be explicit can be done, and is a good idea for other reasons. Once something like that exists then the problem is the 'foo' symbol -- that's why the optional-parens get in the way. I'm just saying that doing that might be possible, not that it will happen in the current D incarnation. For some reason some people seem to like the optional parens. :^) artur
Jul 03 2013
prev sibling next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 3 July 2013 at 14:52:32 UTC, John Colvin wrote:
 Is there any way to take the address of any of an overloaded 
 set of functions?

 import std.stdio;

 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }

 void main()
 {
     auto b = &foo; //ambiguous => error
     b(2); //valid for either overload
 }
http://dpaste.dzfl.pl/1e705a3b
Jul 03 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Wednesday, 3 July 2013 at 15:05:00 UTC, Dicebot wrote:
 On Wednesday, 3 July 2013 at 14:52:32 UTC, John Colvin wrote:
 Is there any way to take the address of any of an overloaded 
 set of functions?

 import std.stdio;

 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }

 void main()
 {
    auto b = &foo; //ambiguous => error
    b(2); //valid for either overload
 }
http://dpaste.dzfl.pl/1e705a3b
It's a pity that only work within an aggregate (the documentation actually says only classes)
Jul 03 2013
next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/03/13 17:17, John Colvin wrote:
 On Wednesday, 3 July 2013 at 15:05:00 UTC, Dicebot wrote:
 On Wednesday, 3 July 2013 at 14:52:32 UTC, John Colvin wrote:
 Is there any way to take the address of any of an overloaded set of functions?

 import std.stdio;

 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }

 void main()
 {
    auto b = &foo; //ambiguous => error
    b(2); //valid for either overload
 }
http://dpaste.dzfl.pl/1e705a3b
It's a pity that only work within an aggregate (the documentation actually says only classes)
http://forum.dlang.org/thread/xamuenbcabnhrtqjjizw forum.dlang.org#post-mailman.1122.1332633715.4860.digitalmars-d-learn:40puremagic.com artur
Jul 03 2013
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 3 July 2013 at 15:17:49 UTC, John Colvin wrote:
 It's a pity that only work within an aggregate (the 
 documentation actually says only classes)
http://dpaste.dzfl.pl/6866e094 Surprise! :P
Jul 04 2013
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 4 July 2013 at 09:15:30 UTC, Dicebot wrote:
 On Wednesday, 3 July 2013 at 15:17:49 UTC, John Colvin wrote:
 It's a pity that only work within an aggregate (the 
 documentation actually says only classes)
http://dpaste.dzfl.pl/6866e094 Surprise! :P
Hooray :) I've submitted a pull request to fix the documentation.
Jul 04 2013
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/03/13 17:03, Artur Skawina wrote:
 On 07/03/13 16:52, John Colvin wrote:
 Is there any way to take the address of any of an overloaded set of functions?

 import std.stdio;

 void foo(int a){ writeln("overload int"); }
 void foo(long b){ writeln("overload long"); }

 void main()
 {
     auto b = &foo; //ambiguous => error
     b(2); //valid for either overload
 }
void function(long) b = &foo;
And if you meant for the overload resolution to happen at call-time, that's obviously not directly possible - there's no address of a /set/ of functions. You can use an alias, though: alias b = foo; artur
Jul 03 2013