July 03, 2013
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
July 03, 2013
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
July 03, 2013
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
July 03, 2013
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.
July 03, 2013
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
July 03, 2013
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.
July 03, 2013
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
July 03, 2013
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");
}
July 04, 2013
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
July 04, 2013
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