April 26, 2012
On Wed, Apr 25, 2012 at 10:39:01PM -0700, Walter Bright wrote:
> On 4/25/2012 10:29 PM, Ary Manzana wrote:
> >I don't understand the relationship between two delegate types being the same and thus sharing the same implementation for default arguments for *different instances* of a delegate with the same type.
> >
> >Maybe a bug in how it's currently implemented?
> 
> If you call a delegate directly, then the default arguments work. If you call it indirectly, the default arguments won't work.

This is even more an argument for *not* including default arguments in the type.


T

-- 
IBM = I Blame Microsoft
April 26, 2012
On Apr 25, 2012, at 9:10 PM, Walter Bright <newshound2@digitalmars.com> wrote:

> On 4/25/2012 8:44 PM, Walter Bright wrote:
>> The problem centers around name mangling. If two types mangle the same, then they are the same type. But default arguments are not part of the mangled string. Hence the schizophrenic behavior.
> 
> One might suggest mangling the default argument into the type. But default arguments need not be compile time constants - they are evaluated at runtime! Hence the unattractive specter of trying to mangle a runtime expression.

Sounds to me like you just answered your own question :-)
April 26, 2012
"Walter Bright" <newshound2@digitalmars.com> wrote in message news:jnagar$2d8k$1@digitalmars.com...
>A subtle but nasty problem - are default arguments part of the type, or part of the declaration?
>
>    See http://d.puremagic.com/issues/show_bug.cgi?id=3866
>
> Currently, they are both, which leads to the nasty behavior in the bug report.
>
> The problem centers around name mangling. If two types mangle the same, then they are the same type. But default arguments are not part of the mangled string. Hence the schizophrenic behavior.
>
> But if we make default arguments solely a part of the function declaration, then function pointers (and delegates) cannot have default arguments. (And maybe this isn't a bad thing?)

From what I remember, function pointer parameter names have similar problems.  It never made any sense to me to have default parameters or parameter names as part of the type.


April 26, 2012
On Thursday, April 26, 2012 13:54:47 bearophile wrote:
> The simplest solution is to the breaking change of disallowing default arguments for function pointers and delegates. This also means disallowing talking the pointer/delegate of function with default arguments.

No it doesn't. You could definitely have a pointer to function with default arguments. It's just that the pointer doesn't use the default arguments at all. The default arguments get inserted at the call site if you explicitly call a function and don't pass arguments for those parameters. The function's signature is unaffected by the presence of default arguments, so the pointer should be unaffected.

What should be disallowed is giving default arguments to function pointers and delegate literals. So, stuff like

void main()
{
 int foo(int a = 1)
 {
 return a;
 }
}

should work just fine. The default argument will only get used if foo is called directly. However, stuff like

void main()
{
 auto foo = (int a = 1) { return a;};
}

wouldn't work, because you can't call the function except through its pointer. As you can never call the function directly, its default argument would never be used, and there would be no point to having it.

- Jonathan M Davis
April 26, 2012
On Thursday, April 26, 2012 15:09:15 Joseph Rushton Wakeling wrote:
> On 26/04/12 05:44, Walter Bright wrote:
> > But if we make default arguments solely a part of the function
> > declaration, then function pointers (and delegates) cannot have default
> > arguments. (And maybe this isn't a bad thing?)
> 
> I can't see disallowing default arguments as being a good thing. For example, instead of,
> 
> void foo(int a, int b = 2)
> {
> ...
> }
> 
> surely I can just put instead
> 
> void foo(int a, int b)
> {
> ...
> }
> 
> void foo(int a)
> {
> foo(a, 2);
> }
> 
> ... and surely I can do something similar for function pointers and delegates. So, I can still have default arguments in effect, I just have to work more as a programmer, using a less friendly and easy-to-understand syntax. That doesn't really seem like a good way to operate unless there's an extreme level of complication in getting the compiler to handle the situation.

There is an _enormous_ difference between disallowing default arguments in general and disallowing them in function pointers and delegates.

Think about how function pointers and delegates get used. They're almost always called generically. Something gets passed a function pointer or delegate and argument and calls it. The caller isn't going to care about default arguments. It expects a specific signature and passes those specific arguments to the function/delegate when it calls it. It's not going to be calling it with 2 arguments in one case and 3 in another.

No default arguments are involved with function pointers in C/C++, and I've never heard of anyone complain about it there. Default arguments are great when you're going to be calling a function in a variety of places, and you want defaults for some parameters in cases where they're almost always a particular value so that you don't have to always type them. But function pointers and delegates are generally called in _one_ way, if not in one place, so their usage is _very_ different.

- Jonathan M Davis
April 26, 2012
On 26/04/12 19:25, Jonathan M Davis wrote:
> There is an _enormous_ difference between disallowing default arguments in
> general and disallowing them in function pointers and delegates.

I think maybe I've misunderstood the problem.  Are we talking about default values _of the function pointer_ or that get passed to the function pointer?

i.e. are we talking about,

    int foo(int delegate() dg = &bar) {
        ...
    }

or about

    int foo(int delegate() dg = &bar) {
        bar();  // assumes default arguments for bar
    }

...?
April 26, 2012
On Thu, 26 Apr 2012 06:10:14 +0200, Walter Bright <newshound2@digitalmars.com> wrote:

> On 4/25/2012 8:44 PM, Walter Bright wrote:
>> The problem centers around name mangling. If two types mangle the same, then
>> they are the same type. But default arguments are not part of the mangled
>> string. Hence the schizophrenic behavior.
>
> One might suggest mangling the default argument into the type. But default arguments need not be compile time constants - they are evaluated at runtime! Hence the unattractive specter of trying to mangle a runtime expression.

import std.stdio;

int readVal()
{
    int val;
    stdin.readf("%s", &val);
    return val;
}

void main()
{
    auto dg = (int a=readVal()) => a;
    writeln(dg());
}

----

Stuffing the value into the type is not going to work out when taking the address.
I think it would be interesting to transform them to values of a type that
preserves the behavior. This would work for polymorphic lambdas as values too.

----
auto dg = (int a=readVal()) => a;

static struct Lamba
{
  int opCall() { return fbody(readVal()); }
  int opCall(int a) { return fbody(a); }
  int function(int) opAddrOf() { return &fbody; }
  static int fbody(int a) { return a; }
}

----
auto dg = a => 2 * a;

struct Lambda
{
  auto opCall(Ta)(auto ref Ta a) { return fbody(a); }
  @disable opAddrOf();
  /*static*/ auto fbody(Ta)(Ta a) { return 2 * a; }
}
April 26, 2012
On Thursday, April 26, 2012 19:45:55 Joseph Rushton Wakeling wrote:
> On 26/04/12 19:25, Jonathan M Davis wrote:
> > There is an _enormous_ difference between disallowing default arguments in general and disallowing them in function pointers and delegates.
> 
> I think maybe I've misunderstood the problem. Are we talking about default values _of the function pointer_ or that get passed to the function pointer?
> 
> i.e. are we talking about,
> 
> int foo(int delegate() dg = &bar) {
> ...
> }
> 
> or about
> 
> int foo(int delegate() dg = &bar) {
> bar(); // assumes default arguments for bar
> }

The second. If you have

int foo(int a = 1)
{
 return a + 3;
}

and you call foo directly without any arguments, then the default argument would be inserted. The problem is when you have a pointer to foo. Should calls to the pointer use a default argument or not? To do that, they need to be part of the type of the function pointer (or delegate).

Personally, I think that it's a very clear and resounding _no_. Default arguments are merely syntactic sugar (albeit very useful syntactic sugar) and should _not_ affect the type of a function pointer or delegate. A function pointer shouldn't care about whatever default arguments its function might have, and a pointer to the foo above should have the same type as a pointer to

int bar(int a)
{
 return a - 2;
}

As such, code like

auto foo = (int a = 1) { return a;};

should probably be illegal, since the default argument could never be used. Right now, we get very weird behavior due to an attempt to make such things work. And I think that it's pretty clear that that was a mistake (though obviously this discussion is to gauge what the group as a whole think and debate it if necessary).

- Jonathan M Davis
April 26, 2012
>    int function(int) opAddrOf() { return &fbody; }

That was wrong, this should be supported through implicit conversion.
April 26, 2012
On 4/26/2012 8:06 AM, Sean Kelly wrote:
> Sounds to me like you just answered your own question :-)

Pretty much. I posted it here to see if I missed something major. Not that that ever happens :-)