Thread overview
__traits(getDelegate, ...)
Feb 04, 2013
deadalnix
Feb 04, 2013
Jacob Carlborg
February 04, 2013
I wanted to put forth again a proposal I had for getting a delegate to an overloaded function.  Only because I think it's relevant to the latest property debate.

When getting the address of a delegate, it's as simple as:

struct S
{
   void foo(int x) {}
}

S s;
auto dg = &s.foo; // delegate obtained

However, if foo is overloaded, this becomes more complex:

struct S
{
   void foo(int x) {}
   void foo(string s) {}
}

S s;
auto dg = &s.foo; // which one?  Compiler chooses!

Turns out, it's somewhat possible to specify, but it can be painful/uintuitive:

auto dg = cast(void delegate(string))&s.foo; // oops, what if I use the wrong delegate signature, or S.foo is changed later!

How about getting a delegate using __traits?

auto dg = __traits(getDelegate, s.foo, string);

Maybe not quite as pretty as &s.foo, but at least allows you to form a good expression without a cast.

Now, why is this relevant now?  It could be useful for properties as well.  It could allow obtaining a delegate to a property (arguably a very rare occurrence), where the current property proposal uses a funky parentheses technique for it (which seems unintuitive for a C expression to be changed by adding parentheses).

Full proposal:

__traits(getDelegate, symbol, arg1, arg2, ..., argN)

The args are optional, only needed if overloads exist.  If overloads exist, args MUST be specified (to protect against future changes).  In the special case where one of the overloads has no arguments, void must be specified for that overload.

Rules/syntax subject to debate.

Destroy!

-Steve
February 04, 2013
On 2/4/13 12:14 AM, Steven Schveighoffer wrote:
> I wanted to put forth again a proposal I had for getting a delegate to
> an overloaded function. Only because I think it's relevant to the latest
> property debate.
>
> When getting the address of a delegate, it's as simple as:
>
> struct S
> {
> void foo(int x) {}
> }
>
> S s;
> auto dg = &s.foo; // delegate obtained
>
> However, if foo is overloaded, this becomes more complex:
>
> struct S
> {
> void foo(int x) {}
> void foo(string s) {}
> }
>
> S s;
> auto dg = &s.foo; // which one? Compiler chooses!
>
> Turns out, it's somewhat possible to specify, but it can be
> painful/uintuitive:
>
> auto dg = cast(void delegate(string))&s.foo; // oops, what if I use the
> wrong delegate signature, or S.foo is changed later!

void delegate(string) dg = &s.foo;

Andrei
February 04, 2013
On Mon, 04 Feb 2013 00:20:22 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 2/4/13 12:14 AM, Steven Schveighoffer wrote:
>> Turns out, it's somewhat possible to specify, but it can be
>> painful/uintuitive:
>>
>> auto dg = cast(void delegate(string))&s.foo; // oops, what if I use the
>> wrong delegate signature, or S.foo is changed later!
>
> void delegate(string) dg = &s.foo;

That seems, ... odd.  How does the lhs dictate the rhs expression type?

Trying to think of a case where an expression is more handy than assigning to a variable first...

Possibly this?  Kind of a stretch.

void delayedCall(D)(D dg)
{
   // put dg as a delegate onto a message queue to call later...
}

-Steve
February 04, 2013
On 2/4/13 12:32 AM, Steven Schveighoffer wrote:
> On Mon, 04 Feb 2013 00:20:22 -0500, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> On 2/4/13 12:14 AM, Steven Schveighoffer wrote:
>>> Turns out, it's somewhat possible to specify, but it can be
>>> painful/uintuitive:
>>>
>>> auto dg = cast(void delegate(string))&s.foo; // oops, what if I use the
>>> wrong delegate signature, or S.foo is changed later!
>>
>> void delegate(string) dg = &s.foo;
>
> That seems, ... odd. How does the lhs dictate the rhs expression type?
>
> Trying to think of a case where an expression is more handy than
> assigning to a variable first...
>
> Possibly this? Kind of a stretch.
>
> void delayedCall(D)(D dg)
> {
> // put dg as a delegate onto a message queue to call later...
> }
>
> -Steve

This is well-trodden ground. The rule has been in C++ forever and has worked well. It's time-proven, and there is little reason to mess with what works.

Andrei
February 04, 2013
On Mon, 04 Feb 2013 00:39:04 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> This is well-trodden ground. The rule has been in C++ forever and has worked well. It's time-proven, and there is little reason to mess with what works.

Fair enough.  Withdrawn.

-Steve
February 04, 2013
On Monday, 4 February 2013 at 05:39:04 UTC, Andrei Alexandrescu wrote:
> This is well-trodden ground. The rule has been in C++ forever and has worked well. It's time-proven, and there is little reason to mess with what works.
>

C++ is notoriously confusing, odd, weird, and basically any adjective except straightforward, simple and clear.
February 04, 2013
On 2013-02-04 06:20, Andrei Alexandrescu wrote:

> void delegate(string) dg = &s.foo;

I know that this expression works. But since this works, why can't we overload on the return value. This seems to be do exactly this. The arguments I heard against overloading on the return value is due the LHS of an expression shouldn't affect the RHS.

-- 
/Jacob Carlborg
February 04, 2013
On 2/4/13 3:01 AM, Jacob Carlborg wrote:
> On 2013-02-04 06:20, Andrei Alexandrescu wrote:
>
>> void delegate(string) dg = &s.foo;
>
> I know that this expression works. But since this works, why can't we
> overload on the return value. This seems to be do exactly this. The
> arguments I heard against overloading on the return value is due the LHS
> of an expression shouldn't affect the RHS.

I think overloading on the return value of functions can be made to work. I understand how it makes it more difficult on the side of the compiler writer, but it's not impossible. The main argument against it is that it adds yet another layer of difficulty in name resolution for function calls.

Andrei