Keyword Args
Difference (last change) (Author, normal page display)
Changed: 163,164c163
In Lisp... |
Python allows arguments to be specified (optionally) by keyword, but doesn't allow overloading. (I.e. functions cannot be overloaded by type or number as they can in D.) |
Changed: 167,170c166,170
Most of the issues are unresolved at this time. <g> The main issue that comes to mind is that matching overloaded versions of functions becomes more complicated to implement. But I don't think it's impossible. |
* Function name mangling would have to be extended to include the keyword names, as this info would have to be present in compiled libs. * More thinking needs to be done about how this would interfere with or complicate the matching process used to deduce which version of an overloaded function to call. * The practice of using no-name arguments in declarations or for unused parameters may cause conflicts ( i.e. currently it is ok to define a function "void foo(int,int) {}" if you don't need to use the parameters in the body. Similarly it's ok to have "void foo{int,int);" in a header file and "void foo(int a, int b){}" as the actual definition. * For method overrides, do the argument names have to match the ones used in the parent class? What if they don't? * Since declarations can be extracted from a D source file to create a sort of header file, some conflict resolution policy would have to be decided upon if the declaration in a header file differed from the actual definition. |
Deleted: 172d171
Also the C/C++ practice of no-name arguments in types may cause conflicts. |
Keyword Arguments
A proposal for allowing named keyword arguments for functions and templates.
The Issue
The 'C++' style of function and template arguments inherited by D has some limitations.
- Having to provide many unnecessary defaults
- Unclear meaning of arguments at call time
- Flexibility and maintainability of code when argument lists are changed
- Difficulty of rememebering order of seldom-used arguments
Too many defaults
Functions and templates can sometimes grow a lot of arguments. Currently you can specify an argument list with defaults like:
![]() |
|
You can then call aFunction leaving out the last few arguments, and default values will be supplied. Unfortunately, you can't just supply arg4 without also supplying arg3. And it's up to you to remember the order of all the arguments. This problem is often seen to its extreme in GUI toolkits, where widget creation functions take many many parameters.
If you could call using keywords or named arguments like in some other programming languages (e.g. Python, Lisp) then the problem would be solved:
![]() |
|
Here's a typical example of a constructor from wxWidgets:
![]() |
|
To specify the name, for instance, you have to supply 3 additional unrelated arguments: pos,size, and style.
So you have to do:
![]() |
|
Instead of the much clearer and more maintainable alternative possible with keyword arguments:
![]() |
|
Unclear meaning
Lack of readability at the place of call is another problem. Consider a function with one or more boolean arguments. It is common to make a function with a few bool paramters like:
![]() |
|
This may not be considered good practice, but it's very easy to do, so people are going to do it one way or another. The problem is that at the point of call you have something like:
![]() |
|
and then you have to go back to the definition of the method to see what false and true mean there.
If you want to have meaningful boolean parameters you can define some enums like
![]() |
|
but that's extra work, and also it introduces more symbols into the namespace. Usually to prevent clashes such enums get names like:
![]() |
|
So the call ends up looking very ugly, like:
![]() |
|
And even then its STILL not clear looking at it what's being locked. So you could introduce even more enums like {LOCK X ON}? {LOCK X OFF}?, and use those. But then (if you make them real enums) you're introducing several new enum types. Wow that's getting complicated. We've introduce 2 public enum types with 2 public values each just to be able to call this silly function.
On the other hand, if you have named keyword arguments then you can just call it like:
![]() |
|
The above code is perfectly clear to read, and no silly enums were required.
Maintainability
But now suppose we want to add another argument in before lock_x, and lock_y. We can still do it without messing up existing code:
![]() |
|
Then our manipulate(scale, lock_y=true) call is still valid.
Not Having to Remember Order
It's easy to forget the proper order for arguments. Was it set_item(index,value) or set_item(value,index)? With keyword arguments you don't have to rememeber.
![]() |
|
You just have to remember their names. Which is sometimes easier if a library uses consistent naming conventions.
Templates
All of the above also goes for specifying template parameters too.
Syntax
There are two clear candidates
![]() |
|
or
![]() |
|
The first one is reminiscent of default parameter declarations:
![]() |
|
The second one is reminiscent of structure initializers:
![]() |
|
I prefer the first because it looks more intuitive to me, but the second is probably a closer semantic match with setting argument values via keywords.
Ideally I'd like static array initializers to change to c=4 type syntax.
Summary of Keyword Arguments in other Languages
In Python:
Unresolved Issues
- Function name mangling would have to be extended to include the keyword names, as this info would have to be present in compiled libs.
- More thinking needs to be done about how this would interfere with or complicate the matching process used to deduce which version of an overloaded function to call.
- The practice of using no-name arguments in declarations or for unused parameters may cause conflicts ( i.e. currently it is ok to define a function "void foo(int,int) {}" if you don't need to use the parameters in the body. Similarly it's ok to have "void foo{int,int);" in a header file and "void foo(int a, int b){}" as the actual definition.
- For method overrides, do the argument names have to match the ones used in the parent class? What if they don't?
- Since declarations can be extracted from a D source file to create a sort of header file, some conflict resolution policy would have to be decided upon if the declaration in a header file differed from the actual definition.