www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - What to do about default function arguments

reply Walter Bright <newshound2 digitalmars.com> writes:
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?)
Apr 25 2012
next sibling parent "Nathan M. Swan" <nathanmswan gmail.com> writes:
On Thursday, 26 April 2012 at 03:44:27 UTC, Walter Bright wrote:
 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?)

I don't think it's a bad thing: default arguments in the type system mean values in the type system. NMS
Apr 25 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, April 25, 2012 20:44:07 Walter Bright wrote:
 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?)

Can function pointers have default arguments in C? Honestly, it strikes me as rather bizarre for them to have default arguments. I really don't think that they buy you much. If you use the function or delegate immediately after declaring it (as is typically the case when they're nested), then you could have just just put the default argument in the function itself and not have it as a parameter. And if you're holding on to a function or delegate long term, you're almost certainly going to be using it generically, in which case I wouldn't expect a default argument to make sense there often either. I'd vote to just disallow default arguments for function pointers and delegates. - Jonathan M Davis
Apr 25 2012
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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.
Apr 25 2012
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
On Apr 25, 2012, at 9:10 PM, Walter Bright <newshound2 digitalmars.com> wrot=
e:

 On 4/25/2012 8:44 PM, Walter Bright wrote:
 The problem centers around name mangling. If two types mangle the same, t=


 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=

e! Hence the unattractive specter of trying to mangle a runtime expression. Sounds to me like you just answered your own question :-)=
Apr 26 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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 :-)
Apr 26 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 26/04/2012 20:49, Walter Bright a écrit :
 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 :-)

Why does default argument should be mangled at all ?
Apr 26 2012
prev sibling next sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
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; } }
Apr 26 2012
prev sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
    int function(int) opAddrOf() { return &fbody; }

That was wrong, this should be supported through implicit conversion.
Apr 26 2012
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Apr 25, 2012 at 08:44:07PM -0700, Walter Bright wrote:
 A subtle but nasty problem - are default arguments part of the type,
 or part of the declaration?

My intuition suggests they are part of the declaration, but not part of the type. For example, you could have two functions: void f(int a, int b); void g(int a, int b=1); Are they the same type? I say yes, because both functions accept two int arguments. Nothing about g suggests that it's any different from f, except for the syntactic sugar that you can write g(1) instead of g(1,1). So the default argument really is just part of the declaration, not the type.
    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.

This is bad. What if you have two delegates with different default arguments? What would this code do: auto foo = (int a=1) { return a; }; auto bar = (int a=2) { return a; }; writeln(foo()); writeln(bar()); ?
 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 see default arguments as syntactic sugar; they are to avoid typing commonly used trailing arguments repeatedly. They don't make sense in the context of func ptrs and delegates because presumably you're using a func ptr or a delegate for generic handling, as Jonathan said, so you wouldn't be relying on default arguments anyway. So default arguments aren't really useful in this case. No big loss if we lose them. T -- Computers aren't intelligent; they only think they are.
Apr 25 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/25/2012 9:42 PM, H. S. Teoh wrote:
 This is bad. What if you have two delegates with different default
 arguments? What would this code do:

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

 ?

Give you two error messages, because default arguments wouldn't be allowed for delegates.
Apr 25 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/25/2012 10:20 PM, H. S. Teoh wrote:
 On Wed, Apr 25, 2012 at 10:08:26PM -0700, Walter Bright wrote:
 On 4/25/2012 9:42 PM, H. S. Teoh wrote:
 This is bad. What if you have two delegates with different default
 arguments? What would this code do:

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

 ?

Give you two error messages, because default arguments wouldn't be allowed for delegates.

No I mean the current behaviour. And I just checked: dmd compiles it fine, and prints 1 for both cases (which is wrong).

Hence the problem :-)
Apr 25 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Apr 25, 2012 at 10:08:26PM -0700, Walter Bright wrote:
 On 4/25/2012 9:42 PM, H. S. Teoh wrote:
This is bad. What if you have two delegates with different default
arguments? What would this code do:

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

?

Give you two error messages, because default arguments wouldn't be allowed for delegates.

No I mean the current behaviour. And I just checked: dmd compiles it fine, and prints 1 for both cases (which is wrong). T -- EMACS = Extremely Massive And Cumbersome System
Apr 25 2012
prev sibling next sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 4/26/12 11:44 AM, Walter Bright wrote:
 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?)

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?
Apr 25 2012
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
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.
Apr 25 2012
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
Apr 26 2012
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 26 April 2012 at 03:44:27 UTC, Walter Bright wrote:
 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.

From what I would name "normative" view they should be the same type: function type is charcterized by return type and by number and order of parameters' types. Because both functions accept and return the same types they should be the same function type. On the other hand, D is an ongoing project and you are free to implement special behavior.
 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.

I think it should be done in reverse order: firstly decide whether they are the same or not, than apply mangling to the decision. Tail doesn't wag a dog.
 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?)

The bad thing is that we would need extra typing, the good thing is that if the declaration changes the bug wouldn't be hidden. That I find similar to the D policy of preventing function hijacking, etc.
Apr 25 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/26/2012 05:44 AM, Walter Bright wrote:
 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,

That is how it should be.
 which leads to the nasty behavior in the bug report.

It contributes, but it is not the main cause.
 The problem centers around name mangling. If two types mangle the same,
 then they are the same type.

Then they are equal types.
 But default arguments are not part of the
 mangled string. Hence the schizophrenic behavior.

The schizophrenic behavior occurs because the types cross-talk. Are mangled names kept unique in the compiler or what is the implementation issue exactly?
 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 think default arguments for delegates and function pointers are quite a feat. The proposal is to change the language in a backwards-incompatible way based on implementation issues that shouldn't be that hard to resolve. (Related: Template instantiation should strip off the default arguments from delegate and function pointer types.)
Apr 26 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/26/2012 12:47 AM, Timon Gehr wrote:
 On 04/26/2012 05:44 AM, Walter Bright wrote:
 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,

That is how it should be.
 which leads to the nasty behavior in the bug report.

It contributes, but it is not the main cause.
 The problem centers around name mangling. If two types mangle the same,
 then they are the same type.

Then they are equal types.

This is simply not tenable. What defines when they are "equal" types and when they are "not equal"? Consider a pointer to a function. Are the default arguments part of its type? If it compares "equal" to another type without default arguments, which is the real type (such as the result of ?:) ?
 But default arguments are not part of the
 mangled string. Hence the schizophrenic behavior.

The schizophrenic behavior occurs because the types cross-talk. Are mangled names kept unique in the compiler or what is the implementation issue exactly?

It's a conceptual issue. When is one type the same as another, and when is it not?
Apr 26 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/26/2012 09:54 AM, Walter Bright wrote:
 On 4/26/2012 12:47 AM, Timon Gehr wrote:
 On 04/26/2012 05:44 AM, Walter Bright wrote:
 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,

That is how it should be.
 which leads to the nasty behavior in the bug report.

It contributes, but it is not the main cause.
 The problem centers around name mangling. If two types mangle the same,
 then they are the same type.

Then they are equal types.

This is simply not tenable. What defines when they are "equal" types and when they are "not equal"?

This is a matter of terminology. For example, for 'equal' just exclude the default parameters from the comparison. For 'the same' include default parameters in the comparison. (therefore, 'the same' implies 'equal')
 Consider a pointer to a function. Are the
 default arguments part of its type?

Yes.
 If it compares "equal" to another type without default arguments, which is the
real type (such as the
 result of ?:) ?

The result of ?: is the type of the two arguments if they are the same, and it is the equal type without default arguments if they are not the same.
 But default arguments are not part of the
 mangled string. Hence the schizophrenic behavior.

The schizophrenic behavior occurs because the types cross-talk. Are mangled names kept unique in the compiler or what is the implementation issue exactly?

It's a conceptual issue. When is one type the same as another, and when is it not?

void function(int) is the same as void function(int) and both are equal void function(int=2) is not the same as void function(int=3), but both are equal.
Apr 26 2012
next sibling parent reply Don Clugston <dac nospam.com> writes:
On 26/04/12 11:21, Timon Gehr wrote:
 On 04/26/2012 09:54 AM, Walter Bright wrote:
 On 4/26/2012 12:47 AM, Timon Gehr wrote:
 On 04/26/2012 05:44 AM, Walter Bright wrote:
 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,

That is how it should be.
 which leads to the nasty behavior in the bug report.

It contributes, but it is not the main cause.
 The problem centers around name mangling. If two types mangle the same,
 then they are the same type.

Then they are equal types.

This is simply not tenable. What defines when they are "equal" types and when they are "not equal"?

This is a matter of terminology. For example, for 'equal' just exclude the default parameters from the comparison. For 'the same' include default parameters in the comparison. (therefore, 'the same' implies 'equal')

The language doesn't have the concepts of "same" and "equal" with respect to types. There is "equal" and "implicitly converts to", but that's not quite the same.
 The schizophrenic behavior occurs because the types cross-talk. Are
 mangled
 names kept unique in the compiler or what is the implementation issue
 exactly?

It's a conceptual issue. When is one type the same as another, and when is it not?

void function(int) is the same as void function(int) and both are equal void function(int=2) is not the same as void function(int=3), but both are equal.

The question was *when* are they same, not how you name them.
Apr 26 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/26/2012 11:54 AM, Don Clugston wrote:
 On 26/04/12 11:21, Timon Gehr wrote:
 On 04/26/2012 09:54 AM, Walter Bright wrote:
 On 4/26/2012 12:47 AM, Timon Gehr wrote:
 On 04/26/2012 05:44 AM, Walter Bright wrote:
 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,

That is how it should be.
 which leads to the nasty behavior in the bug report.

It contributes, but it is not the main cause.
 The problem centers around name mangling. If two types mangle the
 same,
 then they are the same type.

Then they are equal types.

This is simply not tenable. What defines when they are "equal" types and when they are "not equal"?

This is a matter of terminology. For example, for 'equal' just exclude the default parameters from the comparison. For 'the same' include default parameters in the comparison. (therefore, 'the same' implies 'equal')

The language doesn't have the concepts of "same" and "equal" with respect to types. There is "equal" and "implicitly converts to", but that's not quite the same.
 The schizophrenic behavior occurs because the types cross-talk. Are
 mangled
 names kept unique in the compiler or what is the implementation issue
 exactly?

It's a conceptual issue. When is one type the same as another, and when is it not?

void function(int) is the same as void function(int) and both are equal void function(int=2) is not the same as void function(int=3), but both are equal.

The question was *when* are they same, not how you name them.

I think I have answered that. Anyway, probably it is indeed a good idea to get rid of default parameters for delegates and function pointers. The issues are certainly resolvable but the complexity of the resulting feature could not be justified.
Apr 26 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/26/2012 2:21 AM, Timon Gehr wrote:
 This is a matter of terminology. For example, for 'equal' just exclude the
 default parameters from the comparison. For 'the same' include default
 parameters in the comparison. (therefore, 'the same' implies 'equal')

I think this is torturing the semantics.
 The result of ?: is the type of the two arguments if they are the same, and it
 is the equal type without default arguments if they are not the same.

That's the problem - the selection of arbitrary rules.
Apr 26 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/26/2012 08:56 PM, Walter Bright wrote:
 On 4/26/2012 2:21 AM, Timon Gehr wrote:
 This is a matter of terminology. For example, for 'equal' just exclude
 the
 default parameters from the comparison. For 'the same' include default
 parameters in the comparison. (therefore, 'the same' implies 'equal')

I think this is torturing the semantics.
 The result of ?: is the type of the two arguments if they are the
 same, and it
 is the equal type without default arguments if they are not the same.

That's the problem - the selection of arbitrary rules.

It is not entirely arbitrary. Anyway, point taken.
Apr 26 2012
prev sibling next sibling parent reply Don Clugston <dac nospam.com> writes:
On 26/04/12 05:44, Walter Bright wrote:
 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?)

I think it is a mistake to allow default arguments in function pointers and delegates (it's OK for delegate literals, there you have the declaration). I don't see how it can possibly work. If it's really a type, then given: void foo(int x = 2) {} void bar(int y = 3) {} then typeof(&foo) should be: void function (int __param0 = 2) I don't see how we could justify having those types and not using them. But then, if you have: auto p = &foo; // p has default parameter of 2 p = &bar; // Should this work? I really don't think we want this. As I vaguely remember someone saying about the bug report, it looks like an attempt to have a pathetic special case of currying syntax sugar built into the language. But it isn't even as efficient as a library solution (if the construction of the default parameter is expensive, it will generate gobs of code every time the function parameter is called).
Apr 26 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/26/2012 10:51 AM, Don Clugston wrote:
 On 26/04/12 05:44, Walter Bright wrote:
 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?)

I think it is a mistake to allow default arguments in function pointers and delegates (it's OK for delegate literals, there you have the declaration).

The parenthesised part is in conflict with your other statement.
 I don't see how it can possibly work.

 If it's really a type, then given:
 void foo(int x = 2) {}
 void bar(int y = 3) {}
 then typeof(&foo) should be: void function (int __param0 = 2)
 I don't see how we could justify having those types and not using them.

 But then, if you have:
 auto p = &foo; // p has default parameter of 2
 p = &bar; // Should this work?

 I really don't think we want this.

We probably don't.
 As I vaguely remember someone saying about the bug report, it looks like
 an attempt to have a pathetic special case of currying syntax sugar
 built into the language.

I don't see how it relates to currying.
 But it isn't even as efficient as a library solution (if the
 construction of the default parameter is expensive, it will generate
 gobs of code every time the function parameter is called).

Apr 26 2012
parent reply Don Clugston <dac nospam.com> writes:
On 26/04/12 11:28, Timon Gehr wrote:
 On 04/26/2012 10:51 AM, Don Clugston wrote:
 On 26/04/12 05:44, Walter Bright wrote:
 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?)

I think it is a mistake to allow default arguments in function pointers and delegates (it's OK for delegate literals, there you have the declaration).

The parenthesised part is in conflict with your other statement.

No it doesn't. A default argument is a delegate literal is part of the declaration, not part of the type.
Apr 26 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/26/2012 11:46 AM, Don Clugston wrote:
 On 26/04/12 11:28, Timon Gehr wrote:
 On 04/26/2012 10:51 AM, Don Clugston wrote:
 On 26/04/12 05:44, Walter Bright wrote:
 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?)

I think it is a mistake to allow default arguments in function pointers and delegates (it's OK for delegate literals, there you have the declaration).

The parenthesised part is in conflict with your other statement.

No it doesn't. A default argument is a delegate literal is part of the declaration, not part of the type.

If types cannot specify default arguments, then those will be thrown away right away, because what is later called is based on the type of the delegate and not on the implicit function declaration that has its address taken. What is the point of allowing it if it cannot be used?
Apr 26 2012
parent Don Clugston <dac nospam.com> writes:
On 26/04/12 12:11, Timon Gehr wrote:
 On 04/26/2012 11:46 AM, Don Clugston wrote:
 On 26/04/12 11:28, Timon Gehr wrote:
 On 04/26/2012 10:51 AM, Don Clugston wrote:
 On 26/04/12 05:44, Walter Bright wrote:
 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?)

I think it is a mistake to allow default arguments in function pointers and delegates (it's OK for delegate literals, there you have the declaration).

The parenthesised part is in conflict with your other statement.

No it doesn't. A default argument is a delegate literal is part of the declaration, not part of the type.

If types cannot specify default arguments, then those will be thrown away right away, because what is later called is based on the type of the delegate and not on the implicit function declaration that has its address taken. What is the point of allowing it if it cannot be used?

Fair point. It could be used in the case where it is called at the point of declaration (I do that a fair bit), but it's pretty much useless because it is clearer code to put the default parameter in the call. int m = (int a, int b = 3){ return a+b;}(7); Point conceded. So default arguments should be disallowed in delegate literals as well.
Apr 26 2012
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-26 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?)

Why not? -- /Jacob Carlborg
Apr 26 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/26/2012 1:54 AM, Jacob Carlborg wrote:
 On 2012-04-26 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?)

Why not?

Because a function pointer, and delegate, can exist without a corresponding declaration.
Apr 26 2012
prev sibling next sibling parent Trass3r <un known.com> writes:
I've always thought of default arguments to be plain syntactic sugar, so  
for void f(int i, int j=5)    f(1) is simply transformed to f(1,5) and the  
rest is the same.
Apr 26 2012
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2012-04-26 03:44:07 +0000, Walter Bright <newshound2 digitalmars.com> said:

 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?)

Assuming we want to allow it, all you need is to treat the type having the default parameters as a specialization of the type that has none. In other words, the type with the default arugments is implicitly castable to the type without. Should it affect name mangling? Yes and not. It should affect name mangling in the compiler since you're using the mangled name to check for equality between types. But I think it should not affect name mangling for the generated code: the base type without the default arguments should give its name to the emitted symbols so that changing the default argument does not change the ABI. But is it desirable? I'm not convinced. I don't really see the point. It looks like a poor substitute for overloading to me. That said, there was some talk about adding support for named parameters a year ago. For named parameters, I think it'd make sense to have parameter names be part of the type, and little harm would result in adding default parameters too into the mix. As suggested above, it should be implicitly castable to a base type without parameter names or default values. But for default parameters alone, I don't feel the complication is justified. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 26 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
Michel Fortin:

 That said, there was some talk about adding support for named 
 parameters a year ago.

Good reminder. I think such parts of D shouldn't be designed one of a time. If you want to face the problem of default arguments, it's better to think about named arguments too (even if you don't want to implement them now, to not preclude their good future implementation). Bye, bearophile
Apr 26 2012
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 26/04/2012 05:44, Walter Bright a écrit :
 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?)

Maybe the problem is that type are considered to be the same when the mangling is the same. The default parameter is part of the type, isn't mangled (or hell will come on earth) and is covariant with the type with no default.
Apr 26 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Walter:
 A subtle but nasty problem - are default arguments part of the 
 type, or part of the declaration?

I'm waiting for years to see you finally facing this problem too :-) The current situation is not acceptable, so some change of the current situation is required, probably a small breaking change. 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. The advantage of this solution is its simplicity, for both the compiler the D programmer and the D newbie that has to learn D. A second alternative solution is to put the default arguments inside the function mangled and, and to avoid troubles, allow this only for POD data known at compile-time (and throw a compile-time error in all other cases). This has the advantage that common default arguments like "true", 15, 2.5, are accepted, so this gives some flexibility. One disadvantage is that you need to add a special case to D, but it's not a nasty special case, it's a clean thing. A third possible way is to put the default arguments inside the delegate/function itself, as in Python. So default arguments for delegates/function have a different semantics. Then add a hidden extra field to such delegates/functions, a ubyte that tells the function how many arguments are actually given to the function (so the function is later able to use this argument to know how many arguments replace with the default ones). This has some disadvantages, because you can retrofit already compiled modules, so you can't get the function pointer of a function that doesn't have this hidden argument. The advantage is that the semantics is clean, and it's quite flexible. Bye, bearophile
Apr 26 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 25 Apr 2012 23:44:07 -0400, Walter Bright  
<newshound2 digitalmars.com> wrote:

 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?)

Some testing (2.059): void main() { auto a = (int x = 1) { return x;}; auto b = (int x) { return x;}; pragma(msg, typeof(a).stringof); pragma(msg, typeof(b).stringof); } output: int function(int x = 1) pure nothrow safe int function(int x = 1) pure nothrow safe second pass: void main() { auto a = (int x = 1) { return x;}; pure nothrow safe int function(int) b = (int x) { return x;}; pragma(msg, typeof(a).stringof); pragma(msg, typeof(b).stringof); b = a; // ok //a = b; // error //b(); // error } output: int function(int x = 1) pure nothrow safe int function(int) if you ask me, everything looks exactly as I'd expect, except the auto type inference of b. Can this not be fixed? I don't understand the difficulty. BTW, I didn't know you could have default arguments for functions/delegates, it's pretty neat :) -Steve
Apr 26 2012
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
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.
Apr 26 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 26 Apr 2012 09:08:07 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 void main()
 {
      auto a = (int x = 1) { return x;};
      pure nothrow  safe int function(int) b = (int x) { return x;};
      pragma(msg, typeof(a).stringof);
      pragma(msg, typeof(b).stringof);
      b = a; // ok
      //a = b; // error

      //b(); // error
 }

 output:

 int function(int x = 1) pure nothrow  safe
 int function(int)

Nevermind, I just realized it was ignoring my pure nothrow safe for the declaration. Moving it after the declaration results in: void main() { auto a = (int x = 1) { return x;}; int function(int) pure nothrow safe b = (int x) { return x;}; pragma(msg, typeof(a).stringof); pragma(msg, typeof(b).stringof); } output: int function(int x = 1) pure nothrow safe int function(int x = 1) pure nothrow safe which clearly mimics the auto behavior. This is *really* no good, since it seems to be ignoring the explicit type that I specified. IMO, the correct solution is to make the default argument part of the type (and don't let it affect things globally!), and make it derived from the version without a default arg. I think Michel Fortin said the same thing. -Steve
Apr 26 2012
prev sibling next sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"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.
Apr 26 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Apr 26 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Apr 26 2012
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
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 } ...?
Apr 26 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Apr 26 2012
prev sibling parent Manu <turkeyman gmail.com> writes:
--20cf30334cabb8dd9f04be9cecea
Content-Type: text/plain; charset=UTF-8

I've actually been making fairly extensive use of function/delegate default
args. I was pleasantly surprised when I realised it was possible.
Funnily enough, It's one of those things that I just expected should work
(as I find most things I just expect should work do in fact tend to work in
D), so it seems it was intuitive too at some level.

It would be a shame to see it go, but I wouldn't say it's critical, just
very handy. In my case, used in shared interface bindings. Occurs more
often than not in some interfaces.

On 26 April 2012 07:00, Jonathan M Davis <jmdavisProg gmx.com> wrote:

 On Wednesday, April 25, 2012 20:44:07 Walter Bright wrote:
 A subtle but nasty problem - are default arguments part of the type, or

 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,

 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

 then function pointers (and delegates) cannot have default arguments.

 maybe this isn't a bad thing?)

Can function pointers have default arguments in C? Honestly, it strikes me as rather bizarre for them to have default arguments. I really don't think that they buy you much. If you use the function or delegate immediately after declaring it (as is typically the case when they're nested), then you could have just just put the default argument in the function itself and not have it as a parameter. And if you're holding on to a function or delegate long term, you're almost certainly going to be using it generically, in which case I wouldn't expect a default argument to make sense there often either. I'd vote to just disallow default arguments for function pointers and delegates. - Jonathan M Davis

--20cf30334cabb8dd9f04be9cecea Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable I&#39;ve actually been making fairly extensive use of function/delegate def= ault args. I was pleasantly surprised when I realised it was possible.<div>= Funnily enough, It&#39;s one of those things that I just expected should wo= rk (as I find most things I just expect should work do in fact tend to work= in D), so it seems it was intuitive too at some level.</div> <div><br></div><div>It would be a shame to see it go, but I wouldn&#39;t sa= y it&#39;s critical, just very handy. In my case, used in shared interface = bindings. Occurs more often than not in some interfaces.<br><br><div class= =3D"gmail_quote"> On 26 April 2012 07:00, Jonathan M Davis <span dir=3D"ltr">&lt;<a href=3D"m= ailto:jmdavisProg gmx.com">jmdavisProg gmx.com</a>&gt;</span> wrote:<br><bl= ockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #= ccc solid;padding-left:1ex"> <div class=3D"HOEnZb"><div class=3D"h5">On Wednesday, April 25, 2012 20:44:= 07 Walter Bright wrote:<br> &gt; A subtle but nasty problem - are default arguments part of the type, o= r part<br> &gt; of the declaration?<br> &gt;<br> &gt; =C2=A0 =C2=A0 See <a href=3D"http://d.puremagic.com/issues/show_bug.cg= i?id=3D3866" target=3D"_blank">http://d.puremagic.com/issues/show_bug.cgi?i= d=3D3866</a><br> &gt;<br> &gt; Currently, they are both, which leads to the nasty behavior in the bug= <br> &gt; report.<br> &gt;<br> &gt; The problem centers around name mangling. If two types mangle the same= , then<br> &gt; they are the same type. But default arguments are not part of the mang= led<br> &gt; string. Hence the schizophrenic behavior.<br> &gt;<br> &gt; But if we make default arguments solely a part of the function declara= tion,<br> &gt; then function pointers (and delegates) cannot have default arguments. = (And<br> &gt; maybe this isn&#39;t a bad thing?)<br> <br> </div></div>Can function pointers have default arguments in C? Honestly, it= strikes me as<br> rather bizarre for them to have default arguments. I really don&#39;t think= that<br> they buy you much.<br> <br> If you use the function or delegate immediately after declaring it (as is<b= r> typically the case when they&#39;re nested), then you could have just just = put the<br> default argument in the function itself and not have it as a parameter. And= if<br> you&#39;re holding on to a function or delegate long term, you&#39;re almos= t certainly<br> going to be using it generically, in which case I wouldn&#39;t expect a def= ault<br> argument to make sense there often either.<br> <br> I&#39;d vote to just disallow default arguments for function pointers and<b= r> delegates.<br> <span class=3D"HOEnZb"><font color=3D"#888888"><br> - Jonathan M Davis<br> </font></span></blockquote></div><br></div> --20cf30334cabb8dd9f04be9cecea--
Apr 26 2012