Jump to page: 1 2
Thread overview
Request: Implement default arguments properly (unlike C).
Aug 04, 2005
Don Clugston
Aug 04, 2005
AJG
Aug 04, 2005
Don Clugston
Aug 04, 2005
AJG
Aug 04, 2005
Don Clugston
Aug 04, 2005
Don Clugston
Aug 04, 2005
Deewiant
Aug 04, 2005
AJG
Aug 04, 2005
Georg Bauhaus
Aug 04, 2005
AJG
Aug 04, 2005
Georg Bauhaus
Aug 04, 2005
Ben Hinkle
Aug 04, 2005
BCS
Aug 04, 2005
AJG
Aug 04, 2005
BCS
Aug 04, 2005
AJG
Aug 04, 2005
Manfred Nowak
August 04, 2005
It seems that D has inherited the C/C++ semantics for default arguments.  This is an anachronism which IMHO, D should fix.

THE PROBLEM WITH C DEFAULT ARGUMENTS
Consider this code.

int afunc(int x)
{
return x*2;
}

int main()
{
int z = afunc(7);   // A
int function(int) f;
f= &afunc;        // B
int w = f(7);     // C
return w;
}

Obviously A and C are identical calls to afunc().

Now change the declaration of Afunc to
int afunc(int x, int y=3)

Line (A) still works. But line (B) won't compile. Why not?
In line (A), it still looks as though there's a one-parameter function called
afunc(). But it's a fraud. afunc() demands two parameters. The second parameter
is what Herb Sutter calls a "peek-a-boo" parameter: it's hidden most of the
time, but sometimes it pops out unexpectedly and surprises you.
We can change the declaration of f to make B compile, but there's no way to
change line (C) to say 'use the default argument'.

The problem also applies to delegates as well as to function pointers. If you add a default parameter to an existing function, one effect is to break all existing code which delegates to that function.

This is, in my opinion, completely absurd. But a change to the meaning of default arguments would completely solve the problem.

PROPOSAL
The solution is really very simple.

int afunc(int x, int y=3)
{
..dosomething
}

should be *identical* to declaring TWO functions:

int afunc(int x)
{
afunc(x, 3);
}

int afunc(int x, int y)
{
.. dosomething
}

The optimiser can recognise that a call to afunc(7) can be inlined to afunc(7,3), so it would likely generate exactly the same code as before. (Side note: if done in this way, there's actually no reason why the default parameters have to be the last ones. The parser could just check if a function was being redeclared).

All references to default arguments could be stripped out of the parser, except at the point where the declaration is parsed. Everywhere else, it just behaves as an overloaded function. I think this could potentially simplify the language.

I don't know if this would work for templates as well. Since D has template typedefs, perhaps it would. But AFAIK template peek-a-boo arguments aren't the same problem that function parameters are.

I think that the only reason that C default parameters work the way they do is
because when they were introduced, overloading didn't exist.
Now that we have real overloading, the bugs and complexity associated with this
anachronistic "poor mans overloading" can be abolished.

How about it?


August 04, 2005
Hi there,

I am inclined to agree with you regarding the problem (limitation) you mentioned in line "C." At the same time, I'm not so fond of your solution for 2 reasons:

1) Performance: Adding extra function calls would slow things down.
2) Complexity: What happens when you have more than one default parameter? If we
follow your idea, we would get an exponential number of posibilities and
therefore an equal amount of "ghost" functions that would need to be created.
Right?

Having said that, once again I agree that D's default parameters are far from perfect. While we are discussing them, I'll throw in my own complaints (I hope you don't mind):

A) When calling, you can't skip any defaults (Very annoying).
B) Within a class, you can't use member vars as defaults (Ditto).

Cheers,
--AJG.

PS: AFAIK, unlike C++, C doesn't have default parameters.


In article <dcro7a$235c$1@digitaldaemon.com>, Don Clugston says...
>
>It seems that D has inherited the C/C++ semantics for default arguments.  This is an anachronism which IMHO, D should fix.
>
>THE PROBLEM WITH C DEFAULT ARGUMENTS
>Consider this code.
>
>int afunc(int x)
>{
>return x*2;
>}
>
>int main()
>{
>int z = afunc(7);   // A
>int function(int) f;
>f= &afunc;        // B
>int w = f(7);     // C
>return w;
>}
>
>Obviously A and C are identical calls to afunc().
>
>Now change the declaration of Afunc to
>int afunc(int x, int y=3)
>
>Line (A) still works. But line (B) won't compile. Why not?
>In line (A), it still looks as though there's a one-parameter function called
>afunc(). But it's a fraud. afunc() demands two parameters. The second parameter
>is what Herb Sutter calls a "peek-a-boo" parameter: it's hidden most of the
>time, but sometimes it pops out unexpectedly and surprises you.
>We can change the declaration of f to make B compile, but there's no way to
>change line (C) to say 'use the default argument'.
>
>The problem also applies to delegates as well as to function pointers. If you add a default parameter to an existing function, one effect is to break all existing code which delegates to that function.
>
>This is, in my opinion, completely absurd. But a change to the meaning of default arguments would completely solve the problem.
>
>PROPOSAL
>The solution is really very simple.
>
>int afunc(int x, int y=3)
>{
>..dosomething
>}
>
>should be *identical* to declaring TWO functions:
>
>int afunc(int x)
>{
>afunc(x, 3);
>}
>
>int afunc(int x, int y)
>{
>.. dosomething
>}
>
>The optimiser can recognise that a call to afunc(7) can be inlined to afunc(7,3), so it would likely generate exactly the same code as before. (Side note: if done in this way, there's actually no reason why the default parameters have to be the last ones. The parser could just check if a function was being redeclared).
>
>All references to default arguments could be stripped out of the parser, except at the point where the declaration is parsed. Everywhere else, it just behaves as an overloaded function. I think this could potentially simplify the language.
>
>I don't know if this would work for templates as well. Since D has template typedefs, perhaps it would. But AFAIK template peek-a-boo arguments aren't the same problem that function parameters are.
>
>I think that the only reason that C default parameters work the way they do is
>because when they were introduced, overloading didn't exist.
>Now that we have real overloading, the bugs and complexity associated with this
>anachronistic "poor mans overloading" can be abolished.




August 04, 2005
>I am inclined to agree with you regarding the problem (limitation) you mentioned in line "C." At the same time, I'm not so fond of your solution for 2 reasons:
>
>1) Performance: Adding extra function calls would slow things down.

They're just trivial inline functions. If the optimiser can't inline them, it is an extremely poor optimiser. It's one of the most trivial optimisations you can make.

But note that it also gives an opportunity for the compiler to perform
additional optimisation. Suppose that *every* use of the function func(a, b=7)
used the default parameter. Then,  instead of inlining each invocation of the
function, the optimiser could inline the whole of the general func(a, b) into
func(a), turning b into the constant 7. With the existing behaviour, this
optimisation would only be possible with complex whole-program optimisation.
(The this-function-is-only-ever-called-from-one-place optimisation is
much simpler to detect than the
this-function-is-always-called-with-the-same-last-n-parameters optimisation).


If the creation of the default parameters generated a lot of code for constructors etc, and the function was called from many different places, then the compiler might choose to keep it non-inline in order to reduce code size.


>2) Complexity: What happens when you have more than one default parameter? If we follow your idea, we would get an exponential number of posibilities and therefore an equal amount of "ghost" functions that would need to be created. Right?

If we retain compatibility with C++, which is what I'm proposing (ie, only the
final parameters can be defaulted), then it's only a linear number of ghost
functions. Eg
void func(int a=1, int b=2, int c=3, int c=4)
becomes:
func(int a, int b, int c, int d) {}
func(int a, int b, int c) { func(a, b, c, 4); }
func(int a, int b) { func(a, b, 3, 4); }
func(int a) { func(a, 2, 3, 4); }
func() { func(1,2,3,4); }

Even if default parameters could be inserted into an existing list, it is still
only N ghost functions.
eg func(a, b=2, c=3, d=4, e) { dostuff...}
gives
func(a, e) { func(a, 2, 3, 4, e); }
func(a, b, e) { func(a, b, 3, 4, e); }
func(a, b, c, e) { func(a, b, c, 4, e); }
func(a, b, c, d, e) { dostuff... }

I'm not proposing this, but it's a trivial extension. The only reason you might do this is that it might give a more natural parameter ordering.

Complexity would only come if you were allowed to 'skip' parameters; then it's 2^N. Surely this would require some storage of the default parameter list. It would be difficult to maintain existing behaviour in cases where two or more default parameters.

>Having said that, once again I agree that D's default parameters are far from perfect. While we are discussing them, I'll throw in my own complaints (I hope you don't mind):
>
>A) When calling, you can't skip any defaults (Very annoying).
Avoid the 2^N behaviour and the ambiguities would be tricky. Unless you could use , to skip that parameter. Which doesn't sit well with my proposal, because the caller has to know about the existence of default parameters.

>B) Within a class, you can't use member vars as defaults (Ditto).

Now that's an intesting one. I think my proposal would make it much easier to do
that, because when the function is created, you have full access to the class
which created it. Heck, you could have a default which wasn't even constant!
eg.
func(int a, int b=rand()%a) {}
becomes
func(a, b)
func(a) { func(a, rand()%a); } // uses a different value of b every time!

That would be really hard to do with the existing default parameters; the value is stored as a defaultArg member of the Argument struct, and just copied in place. If you had to store an expression, that would be a mess.

Thanks, I think you've just strengthened my case enormously!

>PS: AFAIK, unlike C++, C doesn't have default parameters.

You're probably right. It's been a _very_ long time since I used C.

Cheers,
-Don.


August 04, 2005
I'd like to know how default parameters are actually implemented, however one implementation that wold solve several of these issues comes to mind.

Each possible function signature that uses any default parameters is implemented as a stub that just rearranges the stack and does a goto to the normal function, maybe even inside some of the intro code.

This could work something like tail recursion, thus no extra function calls. As to the "lots of ghost" issue, these stubs would be tiny, ~10-20 op codes maybe a little more if function calls and such are allowed as the defaults. Besides many of these function would get written anyway because the functionality is needed.


In article <dcrrog$25qs$1@digitaldaemon.com>, AJG says...
>1) Performance: Adding extra function calls would slow things down.
>2) Complexity: What happens when you have more than one default parameter? If
>we follow your idea, we would get an exponential number of posibilities and
>therefore an equal amount of "ghost" functions that would need to be created.
>Right?
>
>Having said that, once again I agree that D's default parameters are far from perfect. While we are discussing them, I'll throw in my own complaints (I hope you don't mind):
>
>A) When calling, you can't skip any defaults (Very annoying).
>B) Within a class, you can't use member vars as defaults (Ditto).
>
>Cheers,
>--AJG.
>
>PS: AFAIK, unlike C++, C doesn't have default parameters.
>
>
>In article <dcro7a$235c$1@digitaldaemon.com>, Don Clugston says...
>>
>>It seems that D has inherited the C/C++ semantics for default arguments.  This is an anachronism which IMHO, D should fix.
>>
>>THE PROBLEM WITH C DEFAULT ARGUMENTS
>>Consider this code.
>>
>>int afunc(int x)
>>{
>>return x*2;
>>}
>>
>>int main()
>>{
>>int z = afunc(7);   // A
>>int function(int) f;
>>f= &afunc;        // B
>>int w = f(7);     // C
>>return w;
>>}
>>
>>Obviously A and C are identical calls to afunc().
>>
>>Now change the declaration of Afunc to
>>int afunc(int x, int y=3)
>>
>>Line (A) still works. But line (B) won't compile. Why not?
>>In line (A), it still looks as though there's a one-parameter function called
>>afunc(). But it's a fraud. afunc() demands two parameters. The second parameter
>>is what Herb Sutter calls a "peek-a-boo" parameter: it's hidden most of the
>>time, but sometimes it pops out unexpectedly and surprises you.
>>We can change the declaration of f to make B compile, but there's no way to
>>change line (C) to say 'use the default argument'.
>>
>>The problem also applies to delegates as well as to function pointers. If you add a default parameter to an existing function, one effect is to break all existing code which delegates to that function.
>>
>>This is, in my opinion, completely absurd. But a change to the meaning of default arguments would completely solve the problem.
>>
>>PROPOSAL
>>The solution is really very simple.
>>
>>int afunc(int x, int y=3)
>>{
>>..dosomething
>>}
>>
>>should be *identical* to declaring TWO functions:
>>
>>int afunc(int x)
>>{
>>afunc(x, 3);
>>}
>>
>>int afunc(int x, int y)
>>{
>>.. dosomething
>>}
>>
>>The optimiser can recognise that a call to afunc(7) can be inlined to afunc(7,3), so it would likely generate exactly the same code as before. (Side note: if done in this way, there's actually no reason why the default parameters have to be the last ones. The parser could just check if a function was being redeclared).
>>
>>All references to default arguments could be stripped out of the parser, except at the point where the declaration is parsed. Everywhere else, it just behaves as an overloaded function. I think this could potentially simplify the language.
>>
>>I don't know if this would work for templates as well. Since D has template typedefs, perhaps it would. But AFAIK template peek-a-boo arguments aren't the same problem that function parameters are.
>>
>>I think that the only reason that C default parameters work the way they do is
>>because when they were introduced, overloading didn't exist.
>>Now that we have real overloading, the bugs and complexity associated with this
>>anachronistic "poor mans overloading" can be abolished.
>
>
>
>


August 04, 2005
Hi,

>>I am inclined to agree with you regarding the problem (limitation) you mentioned in line "C." At the same time, I'm not so fond of your solution for 2 reasons:
>>
>>1) Performance: Adding extra function calls would slow things down.
>
>They're just trivial inline functions. If the optimiser can't inline them, it is an extremely poor optimiser. It's one of the most trivial optimisations you can make.

I suppose this is a valid assumption re: optimizer.

>But note that it also gives an opportunity for the compiler to perform
>additional optimisation. Suppose that *every* use of the function func(a, b=7)
>used the default parameter. Then,  instead of inlining each invocation of the
>function, the optimiser could inline the whole of the general func(a, b) into
>func(a), turning b into the constant 7. With the existing behaviour, this
>optimisation would only be possible with complex whole-program optimisation.
>(The this-function-is-only-ever-called-from-one-place optimisation is
>much simpler to detect than the
>this-function-is-always-called-with-the-same-last-n-parameters optimisation).

Hmm... good point. Although I am a fan of whole program static analysis ;).

>If the creation of the default parameters generated a lot of code for constructors etc, and the function was called from many different places, then the compiler might choose to keep it non-inline in order to reduce code size.
>
>>2) Complexity: What happens when you have more than one default parameter? If we follow your idea, we would get an exponential number of posibilities and therefore an equal amount of "ghost" functions that would need to be created. Right?
>
>If we retain compatibility with C++,

But I thought you wanted to move beyond "C++ semantics?" If we're to do this, I think we should get rid of skipping restrictions.

>>Having said that, once again I agree that D's default parameters are far from perfect. While we are discussing them, I'll throw in my own complaints (I hope you don't mind):
>>
>>A) When calling, you can't skip any defaults (Very annoying).
>Avoid the 2^N behaviour and the ambiguities would be tricky. Unless you could use , to skip that parameter. Which doesn't sit well with my proposal, because the caller has to know about the existence of default parameters.

But skipping parameters would be soooooooo nice... ;)

>>B) Within a class, you can't use member vars as defaults (Ditto).
>Now that's an intesting one. I think my proposal would make it much easier to that, because when the function is created, you have full access to the class which created it.

If this is so, then it would definitely be a big step forward. The only thing missing would be skipping parameters, and we'd have awesome functionality.

>Heck, you could have a default which wasn't even constant!
>eg.
>func(int a, int b=rand()%a) {}
>becomes
>func(a, b)
>func(a) { func(a, rand()%a); } // uses a different value of b every time!
>
>That would be really hard to do with the existing default parameters; the value is stored as a defaultArg member of the Argument struct, and just copied in place. If you had to store an expression, that would be a mess.

Hm... I believe non-constant expressions are already allowed:

int Bar() { return (0); }
int Foo(int b = Bar() % 2) { return (b); }
void main() { Foo(); } // Compiles fine.

>Thanks, I think you've just strengthened my case enormously!

No problemo.

>>PS: AFAIK, unlike C++, C doesn't have default parameters.
>You're probably right. It's been a _very_ long time since I used C.

<jealous>
You haven't missed much. We have booleans now.
</jealous>

Cheers,
--AJG.


August 04, 2005
Hi,

In article <dcs3vq$2bmj$1@digitaldaemon.com>, BCS says...
>
>I'd like to know how default parameters are actually implemented, however one implementation that wold solve several of these issues comes to mind.
>
>Each possible function signature that uses any default parameters is as a stub that just rearranges the stack and does a goto to the normal maybe even inside some of the intro code.

Would this allow for skipping parameters, or would it create the 2^N scenario? Or would that not matter?

>This could work something like tail recursion, thus no extra function calls. As
>to the "lots of ghost" issue, these stubs would be tiny, ~10-20 op codes maybe
>little more if function calls and such are allowed as the defaults. Besides
>of these function would get written anyway because the functionality is needed.

Thinking about this a bit more, I wouldn't mind having a lot of ghosts, if it's a flat set of ghosts (meaning one extra call). What I was worried about would be if ghosts called other ghosts arbitrarily, but I guess this wouldn't happen.

Thanks,
--AJG.

>In article <dcrrog$25qs$1@digitaldaemon.com>, AJG says...
>>1) Performance: Adding extra function calls would slow things down.
>>2) Complexity: What happens when you have more than one default parameter? If
>>we follow your idea, we would get an exponential number of posibilities and
>>therefore an equal amount of "ghost" functions that would need to be created.
>>Right?
>>
>>Having said that, once again I agree that D's default parameters are far from perfect. While we are discussing them, I'll throw in my own complaints (I hope you don't mind):
>>
>>A) When calling, you can't skip any defaults (Very annoying).
>>B) Within a class, you can't use member vars as defaults (Ditto).
>>
>>Cheers,
>>--AJG.
>>
>>PS: AFAIK, unlike C++, C doesn't have default parameters.
>>
>>
>>In article <dcro7a$235c$1@digitaldaemon.com>, Don Clugston says...
>>>
>>>It seems that D has inherited the C/C++ semantics for default arguments.  This is an anachronism which IMHO, D should fix.
>>>
>>>THE PROBLEM WITH C DEFAULT ARGUMENTS
>>>Consider this code.
>>>
>>>int afunc(int x)
>>>{
>>>return x*2;
>>>}
>>>
>>>int main()
>>>{
>>>int z = afunc(7);   // A
>>>int function(int) f;
>>>f= &afunc;        // B
>>>int w = f(7);     // C
>>>return w;
>>>}
>>>
>>>Obviously A and C are identical calls to afunc().
>>>
>>>Now change the declaration of Afunc to
>>>int afunc(int x, int y=3)
>>>
>>>Line (A) still works. But line (B) won't compile. Why not?
>>>In line (A), it still looks as though there's a one-parameter function called
>>>afunc(). But it's a fraud. afunc() demands two parameters. The second parameter
>>>is what Herb Sutter calls a "peek-a-boo" parameter: it's hidden most of the
>>>time, but sometimes it pops out unexpectedly and surprises you.
>>>We can change the declaration of f to make B compile, but there's no way to
>>>change line (C) to say 'use the default argument'.
>>>
>>>The problem also applies to delegates as well as to function pointers. If you add a default parameter to an existing function, one effect is to break all existing code which delegates to that function.
>>>
>>>This is, in my opinion, completely absurd. But a change to the meaning of default arguments would completely solve the problem.
>>>
>>>PROPOSAL
>>>The solution is really very simple.
>>>
>>>int afunc(int x, int y=3)
>>>{
>>>..dosomething
>>>}
>>>
>>>should be *identical* to declaring TWO functions:
>>>
>>>int afunc(int x)
>>>{
>>>afunc(x, 3);
>>>}
>>>
>>>int afunc(int x, int y)
>>>{
>>>.. dosomething
>>>}
>>>
>>>The optimiser can recognise that a call to afunc(7) can be inlined to afunc(7,3), so it would likely generate exactly the same code as before. (Side note: if done in this way, there's actually no reason why the default parameters have to be the last ones. The parser could just check if a function was being redeclared).
>>>
>>>All references to default arguments could be stripped out of the parser, except at the point where the declaration is parsed. Everywhere else, it just behaves as an overloaded function. I think this could potentially simplify the language.
>>>
>>>I don't know if this would work for templates as well. Since D has template typedefs, perhaps it would. But AFAIK template peek-a-boo arguments aren't the same problem that function parameters are.
>>>
>>>I think that the only reason that C default parameters work the way they do is
>>>because when they were introduced, overloading didn't exist.
>>>Now that we have real overloading, the bugs and complexity associated with this
>>>anachronistic "poor mans overloading" can be abolished.
>>
>>
>>
>>
>
>


August 04, 2005
Don Clugston <Don_member@pathlink.com> wrote:

[...]
> but there's no
> way to change line (C) to say 'use the default argument'.
[...]

This is the crucial point.

My first thought was, to declare the function variable as

  int function( int, ...) f;

But this does not work, because D seems to treat the ellipsis as a type of its own, which is not documented anywhere.

If this is not a bug, the typesystem of D seems to be broken at at least two points: variadic and default parameters.

-manfred
August 04, 2005
>>But note that it also gives an opportunity for the compiler to perform
>>additional optimisation. Suppose that *every* use of the function func(a, b=7)
>>used the default parameter. Then,  instead of inlining each invocation of the
>>function, the optimiser could inline the whole of the general func(a, b) into
>>func(a), turning b into the constant 7. With the existing behaviour, this
>>optimisation would only be possible with complex whole-program optimisation.
>>(The this-function-is-only-ever-called-from-one-place optimisation is
>>much simpler to detect than the
>>this-function-is-always-called-with-the-same-last-n-parameters optimisation).
>
>Hmm... good point. Although I am a fan of whole program static analysis ;).

Me too. But I'm less confident that I'll get it. Until someone manages to clone Walter.

>>If the creation of the default parameters generated a lot of code for constructors etc, and the function was called from many different places, then the compiler might choose to keep it non-inline in order to reduce code size.
>>
>>>2) Complexity: What happens when you have more than one default parameter? If we follow your idea, we would get an exponential number of posibilities and therefore an equal amount of "ghost" functions that would need to be created. Right?
>>
>>If we retain compatibility with C++,
>
>But I thought you wanted to move beyond "C++ semantics?" If we're to do this, I think we should get rid of skipping restrictions.

Well, it would be a first step, it would close the hole in the language, and I think it wouldn't be too much work. It's kind of a language bug fix. Overcoming the skipping restrictions is new functionality rather than a bug fix.


>>>A) When calling, you can't skip any defaults (Very annoying).
>>Avoid the 2^N behaviour and the ambiguities would be tricky. Unless you could use , to skip that parameter. Which doesn't sit well with my proposal, because the caller has to know about the existence of default parameters.
>
>But skipping parameters would be soooooooo nice... ;)

I agree. I remember some Windows API calls (CreateWindow(), I think) where you specified CW_USEDEFAULT to skip a parameter. It was quite clunky, and I guess the function did the default value substitution itself.

My reservations about this, though, are:
(1) if you have a row of commas in your function call, isn't it going to be a
bit hard to read? Is that four commas, or five?

(2) if you're skipping default values, maybe there's a design flaw somewhere? Default values are just a shortcut way of declaring multiple ways to call the same function (syntactic sugar). If you're skipping some default values but using others, maybe the interface is wrong; maybe you should be adding an extra function, or changing the parameters to be a collection of properties, or something. I'm not certain about this, I'm just a bit uneasy that it might promote bad design. It would be good to provide a concrete example.

>>>B) Within a class, you can't use member vars as defaults (Ditto).
>>Now that's an intesting one. I think my proposal would make it much easier to that, because when the function is created, you have full access to the class which created it.
>
>If this is so, then it would definitely be a big step forward. The only thing missing would be skipping parameters, and we'd have awesome functionality.
>
>>Heck, you could have a default which wasn't even constant!
>>eg.
>>func(int a, int b=rand()%a) {}
>>becomes
>>func(a, b)
>>func(a) { func(a, rand()%a); } // uses a different value of b every time!
>>
>>That would be really hard to do with the existing default parameters; the value is stored as a defaultArg member of the Argument struct, and just copied in place. If you had to store an expression, that would be a mess.
>
>Hm... I believe non-constant expressions are already allowed:
>
>int Bar() { return (0); }
>int Foo(int b = Bar() % 2) { return (b); }
>void main() { Foo(); } // Compiles fine.

OK, it must be copying an entire expression tree. Interesting. But what scope is
that expression in? It won't work in a class, because the defaultArg item
doesn't store a 'this' pointer. (In my proposal, the scope would be inside the
class.)
I tried putting Bar and Foo into a class, and made Bar a static function, with
an interesting result: it compiled OK, but crashed at runtime :)
It works OK if Foo is a static function.

>>>PS: AFAIK, unlike C++, C doesn't have default parameters.
>>You're probably right. It's been a _very_ long time since I used C.
>
><jealous>
>You haven't missed much. We have booleans now.
></jealous>

LOL! But there's a lot to like about C99, they don't seem to have introduced anything really stupid, unlike another language that springs to mind... Sigh...so many poor decisions have been made in the history of C++. I have a real love/hate relationship with C++.

-Don


August 04, 2005
>>But note that it also gives an opportunity for the compiler to perform
>>additional optimisation. Suppose that *every* use of the function func(a, b=7)
>>used the default parameter. Then,  instead of inlining each invocation of the
>>function, the optimiser could inline the whole of the general func(a, b) into
>>func(a), turning b into the constant 7. With the existing behaviour, this
>>optimisation would only be possible with complex whole-program optimisation.
>>(The this-function-is-only-ever-called-from-one-place optimisation is
>>much simpler to detect than the
>>this-function-is-always-called-with-the-same-last-n-parameters optimisation).
>
>Hmm... good point. Although I am a fan of whole program static analysis ;).

Me too. But I'm less confident that I'll get it. Until someone manages to clone Walter.

>>If the creation of the default parameters generated a lot of code for constructors etc, and the function was called from many different places, then the compiler might choose to keep it non-inline in order to reduce code size.
>>
>>>2) Complexity: What happens when you have more than one default parameter? If we follow your idea, we would get an exponential number of posibilities and therefore an equal amount of "ghost" functions that would need to be created. Right?
>>
>>If we retain compatibility with C++,
>
>But I thought you wanted to move beyond "C++ semantics?" If we're to do this, I think we should get rid of skipping restrictions.

Well, it would be a first step, it would close the hole in the language, and I think it wouldn't be too much work. It's kind of a language bug fix. Overcoming the skipping restrictions is new functionality rather than a bug fix.


>>>A) When calling, you can't skip any defaults (Very annoying).
>>Avoid the 2^N behaviour and the ambiguities would be tricky. Unless you could use , to skip that parameter. Which doesn't sit well with my proposal, because the caller has to know about the existence of default parameters.
>
>But skipping parameters would be soooooooo nice... ;)

I agree. I remember some Windows API calls (CreateWindow(), I think) where you specified CW_USEDEFAULT to skip a parameter. It was quite clunky, and I guess the function did the default value substitution itself.

My reservations about this, though, are:
(1) if you have a row of commas in your function call, isn't it going to be a
bit hard to read? Is that four commas, or five?

(2) if you're skipping default values, maybe there's a design flaw somewhere? Default values are just a shortcut way of declaring multiple ways to call the same function (syntactic sugar). If you're skipping some default values but using others, maybe the interface is wrong; maybe you should be adding an extra function, or changing the parameters to be a collection of properties, or something. I'm not certain about this, I'm just a bit uneasy that it might promote bad design. It would be good to provide a concrete example.

>>>B) Within a class, you can't use member vars as defaults (Ditto).
>>Now that's an intesting one. I think my proposal would make it much easier to that, because when the function is created, you have full access to the class which created it.
>
>If this is so, then it would definitely be a big step forward. The only thing missing would be skipping parameters, and we'd have awesome functionality.
>
>>Heck, you could have a default which wasn't even constant!
>>eg.
>>func(int a, int b=rand()%a) {}
>>becomes
>>func(a, b)
>>func(a) { func(a, rand()%a); } // uses a different value of b every time!
>>
>>That would be really hard to do with the existing default parameters; the value is stored as a defaultArg member of the Argument struct, and just copied in place. If you had to store an expression, that would be a mess.
>
>Hm... I believe non-constant expressions are already allowed:
>
>int Bar() { return (0); }
>int Foo(int b = Bar() % 2) { return (b); }
>void main() { Foo(); } // Compiles fine.

OK, it must be copying an entire expression tree. Interesting. But what scope is
that expression in? It won't work in a class, because the defaultArg item
doesn't store a 'this' pointer. (In my proposal, the scope would be inside the
class.)
I tried putting Bar and Foo into a class, and made Bar a static function, with
an interesting result: it compiled OK, but crashed at runtime :)
It works OK if Foo is a static function.

>>>PS: AFAIK, unlike C++, C doesn't have default parameters.
>>You're probably right. It's been a _very_ long time since I used C.
>
><jealous>
>You haven't missed much. We have booleans now.
></jealous>

LOL! But there's a lot to like about C99, they don't seem to have introduced anything really stupid, unlike another language that springs to mind... Sigh...so many poor decisions have been made in the history of C++. I have a real love/hate relationship with C++.

-Don


August 04, 2005
AJG wrote:
> Hm... I believe non-constant expressions are already allowed:
> 
> int Bar() { return (0); }
> int Foo(int b = Bar() % 2) { return (b); }
> void main() { Foo(); } // Compiles fine.

But not if they refer to other arguments, which I think is an important/very useful feature. E.g. in the following function signatures it'd be quite handy:

int foo(int x, int y = x % 2)
int bar(int[] a, int b = a.length)

Currently neither compiles. This (along with every other problem) can be solved using overloading, but that is a _pain_. After all, default arguments should IMO be just syntactic sugar for precisely that, as in the original proposal.

So this is my #1 gripe related to default arguments.
Inability to use members as defaults in a class, which you already
brought earlier, would be #2.
#3 is the problem with function pointers in the original post, but
fortunately I haven't personally run into that problem yet. <g>

I don't really mind not being able to skip defaults, although something like writing "default" in place of a function parameter would doubtless be handy.
« First   ‹ Prev
1 2