www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Passing function parameters by name

reply Artyom Shalkhakov <artyom.shalkhakov gmail.com> writes:
Hello everyone.

I suggest adding a new syntax for function parameter passing. To illustrate:

void foo( int a, float b ) {
    // some code
}

void main() {
    foo( 1, 2.5f ); // classic
    foo( b : 2.5f, a : -3 ); // sort of struct initializer
}

Since named arguments can be passed in any order, they can be especially useful
when a function has more than one parameter with a default value.

This concept could be applied to template instantiation as well.

-Artyom Shalkhakov
Dec 04 2007
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Artyom Shalkhakov:
     foo( b : 2.5f, a : -3 ); // sort of struct initializer
Python uses = foo(b=2.5f, a=-3); This is a very useful feature, I use it often in Python. But if you try to translate this Python code: from sys import argv def a(c="A"): print c def b(c="B"): print c l = [a, b] if argv[1] == "1": l.reverse() l[1]() to D/C++ you can find a problem, becasue the "A" and "B" must be associated with the function. And the function must know what parameters aren't actually given to it. So you may need to silently pass an array of booleans too (and uint/ulong suffices) that encode what parameters you have actually given to the function (there are other solutions, based on pointers, but they seem even slower to me). Bye, bearophile
Dec 04 2007
next sibling parent reply "David Wilson" <dw botanicus.net> writes:
On 12/4/07, bearophile <bearophileHUGS lycos.com> wrote:
 Artyom Shalkhakov:
     foo( b : 2.5f, a : -3 ); // sort of struct initializer
Python uses = foo(b=2.5f, a=-3); This is a very useful feature, I use it often in Python. But if you try to translate this Python code: from sys import argv def a(c="A"): print c def b(c="B"): print c l = [a, b] if argv[1] == "1": l.reverse() l[1]() to D/C++ you can find a problem, becasue the "A" and "B" must be associated with the function. And the function must know what parameters aren't actually given to it. So you may need to silently pass an array of booleans too (and uint/ulong suffices) that encode what parameters you have actually given to the function (there are other solutions, based on pointers, but they seem even slower to me).
This one is pretty close to my heart too, but I can't quite decide what the resulting feature would look like in D. I made an effort to port Python's awesome ElementTree XML library to D, but found most of its convenient syntax was lost because D doesn't support named arguments. A further twist to this is Python's ability to take arbitrary named arguments and build an associative array from them ("dict"). Implementing this feature would probably mean tight integration with AA literal syntax for uniformity's sake, but I couldn't come up with a syntax worth proposing. Desirable: - Ability to specify non-default parameters after default parameters. - Ability to lazy-build an associative array argument to a function, without using AA literal syntax. Rough idea: void foo(int a, bool b = true, bool c = false, char[][char[]] args); foo(0xcafebabe, c: true, strangeArg: "hello", otherArg: "world"); Except I'm sure there's a plethora of things I've forgotten about (interactions with templates for example?) David.
 Bye,
 bearophile
Dec 04 2007
parent reply Artyom Shalkhakov <artyom.shalkhakov gmail.com> writes:
David Wilson Wrote:

 On 12/4/07, bearophile <bearophileHUGS lycos.com> wrote:
 Artyom Shalkhakov:
     foo( b : 2.5f, a : -3 ); // sort of struct initializer
Python uses = foo(b=2.5f, a=-3); This is a very useful feature, I use it often in Python. But if you try to translate this Python code: from sys import argv def a(c="A"): print c def b(c="B"): print c l = [a, b] if argv[1] == "1": l.reverse() l[1]() to D/C++ you can find a problem, becasue the "A" and "B" must be associated with the function. And the function must know what parameters aren't actually given to it. So you may need to silently pass an array of booleans too (and uint/ulong suffices) that encode what parameters you have actually given to the function (there are other solutions, based on pointers, but they seem even slower to me).
This one is pretty close to my heart too, but I can't quite decide what the resulting feature would look like in D. I made an effort to port Python's awesome ElementTree XML library to D, but found most of its convenient syntax was lost because D doesn't support named arguments. A further twist to this is Python's ability to take arbitrary named arguments and build an associative array from them ("dict"). Implementing this feature would probably mean tight integration with AA literal syntax for uniformity's sake, but I couldn't come up with a syntax worth proposing. Desirable: - Ability to specify non-default parameters after default parameters. - Ability to lazy-build an associative array argument to a function, without using AA literal syntax. Rough idea: void foo(int a, bool b = true, bool c = false, char[][char[]] args); foo(0xcafebabe, c: true, strangeArg: "hello", otherArg: "world"); Except I'm sure there's a plethora of things I've forgotten about (interactions with templates for example?) David.
 Bye,
 bearophile
I'm not into getting D so close to Python... I think that the default-parameter-values should remain as-is, with the added ability to address parameters by their name. I suggest looking at D's struct initializers. (Make the process of initializing an array and calling a function more 'uniform'.)
Dec 04 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Artyom Shalkhakov wrote:
 David Wilson Wrote:
 
 On 12/4/07, bearophile <bearophileHUGS lycos.com> wrote:
 Artyom Shalkhakov:
     foo( b : 2.5f, a : -3 ); // sort of struct initializer
Python uses = foo(b=2.5f, a=-3); This is a very useful feature, I use it often in Python. But if you try to translate this Python code: from sys import argv def a(c="A"): print c def b(c="B"): print c l = [a, b] if argv[1] == "1": l.reverse() l[1]() to D/C++ you can find a problem, becasue the "A" and "B" must be associated with the function. And the function must know what parameters aren't actually given to it. So you may need to silently pass an array of booleans too (and uint/ulong suffices) that encode what parameters you have actually given to the function (there are other solutions, based on pointers, but they seem even slower to me).
This one is pretty close to my heart too, but I can't quite decide what the resulting feature would look like in D. I made an effort to port Python's awesome ElementTree XML library to D, but found most of its convenient syntax was lost because D doesn't support named arguments. A further twist to this is Python's ability to take arbitrary named arguments and build an associative array from them ("dict"). Implementing this feature would probably mean tight integration with AA literal syntax for uniformity's sake, but I couldn't come up with a syntax worth proposing. Desirable: - Ability to specify non-default parameters after default parameters. - Ability to lazy-build an associative array argument to a function, without using AA literal syntax. Rough idea: void foo(int a, bool b = true, bool c = false, char[][char[]] args); foo(0xcafebabe, c: true, strangeArg: "hello", otherArg: "world"); Except I'm sure there's a plethora of things I've forgotten about (interactions with templates for example?) David.
 Bye,
 bearophile
I'm not into getting D so close to Python... I think that the default-parameter-values should remain as-is, with the added ability to address parameters by their name. I suggest looking at D's struct initializers. (Make the process of initializing an array and calling a function more 'uniform'.)
I think for any keyword argument proposal to fly, it's going to need to specially mark the keyword args. D's parameter declaration syntax is tied very closely to that of C/C++ and changing that wholesale will break tons of D code and probably make interfacing with C code a confusing mess. In C/C++/D You can declare prototypes using different parameter names from the actual implementation, or with no names at all. This is behavior that is relied upon in many places. However, if the keyword arguments were differentiated from the regular arguments, it might be workable. Lisp uses some kind of token like "&keyword" to separate keyword arguments from others. When calling, the keyword for a keyword arg must always be specified. That sort of things seems like it might be doable in a backwards-compatible way. So something like: void myFunc(int x, &&, float key1=10, float key2=20); ... myFunc(3, key2:10); I think the problem with any keyword arg proposal at this point is that the cost/benefit ratio is low. Thoroughly specing it out and implementing it will be difficult, but the benefit will not be that great. It just adds a little extra convenience. Fixing template overload issues, for instance, would be a much bigger win. Or implementing real reference types. Or Tuples as return values. --bb
Dec 04 2007
prev sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
bearophile wrote:
 to D/C++ you can find a problem, becasue the "A" and "B" must be associated
with the function. And the function must know what parameters aren't actually
given to it. So you may need to silently pass an array of booleans too (and
uint/ulong suffices) that encode what parameters you have actually given to the
function (there are other solutions, based on pointers, but they seem even
slower to me).
The call is bound at compile-time, so there's no runtime cost associated. The default parameters are passed in explicitly for the parameters that the user doesn't supply.
Dec 04 2007
parent reply bearophile <bearophileHUGS lycos.com> writes:
Robert Fraser:
 The call is bound at compile-time,
I can't understand how you can fully solve that problem I have shown at compile time. A function pointer can be managed at runtime, so at runtime you can choose to give or to not give the default parameter... Bye, bearophile
Dec 04 2007
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
bearophile wrote:
 Robert Fraser:
 
The call is bound at compile-time,
I can't understand how you can fully solve that problem I have shown at compile time. A function pointer can be managed at runtime, so at runtime you can choose to give or to not give the default parameter... Bye, bearophile
Function pointers don't know anything about default parameters. That is, the following does not work: void foo(int i=20) {} void main() { void function() fn = &foo; // Error: typeof(&foo) is // void function(int) fn(); } -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Dec 04 2007
parent bearophile <bearophileHUGS lycos.com> writes:
Kirk McDonald Wrote:
 Function pointers don't know anything about default parameters. That is, 
 the following does not work:
I was talking about adding things to D. So it can solve the kind of problem I have shown in my first post. I am talking about possible enhancements... Bye, bearophile
Dec 04 2007
prev sibling next sibling parent reply downs <default_357-line yahoo.de> writes:
You can "sort-of" do function parameters by name by turning the function into a
template, and using some typedefs.

Completely untested example:

 typedef int _Foo;
 _Foo Foo(int e) { return cast(_Foo) e; }

 typedef int _Bar;
 _Bar Bar(int e) { return cast(_Bar) e; }

 void test(T)(T t) {
   static if (is(T==_Bar)) writefln("Got bar: ", t);
   static if (is(T==_Foo)) writefln("Got foo: ", t);
 }

 void main() {
   test(Foo=4); test(Bar=17);
 }
Multiple parameters can be handled with some templates and static ifs as well. :) --downs
Dec 04 2007
parent Robert Fraser <fraserofthenight gmail.com> writes:
downs wrote:
 You can "sort-of" do function parameters by name by turning the function into
a template, and using some typedefs.
 
 Completely untested example:
 
 typedef int _Foo;
 _Foo Foo(int e) { return cast(_Foo) e; }

 typedef int _Bar;
 _Bar Bar(int e) { return cast(_Bar) e; }

 void test(T)(T t) {
   static if (is(T==_Bar)) writefln("Got bar: ", t);
   static if (is(T==_Foo)) writefln("Got foo: ", t);
 }

 void main() {
   test(Foo=4); test(Bar=17);
 }
Multiple parameters can be handled with some templates and static ifs as well. :) --downs
Doing that for every function would be ugly & error-prone, though (even with the magic of nested templates/tuples/mixins).
Dec 04 2007
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
Artyom Shalkhakov wrote:
 Hello everyone.
 
 I suggest adding a new syntax for function parameter passing. To illustrate:
 
 void foo( int a, float b ) {
     // some code
 }
 
 void main() {
     foo( 1, 2.5f ); // classic
     foo( b : 2.5f, a : -3 ); // sort of struct initializer
 }
 
 Since named arguments can be passed in any order, they can be especially
useful when a function has more than one parameter with a default value.
 
 This concept could be applied to template instantiation as well.
 
 -Artyom Shalkhakov
(Genuine question, not a flame): To play devil's advocate for a moment: doesn't a long parameter list or lots of default arguments indicate a poor design? Essentially, the name of the argument becomes part of the API. Why isn't function and object name good enough? Named arguments are potentially a disastrous feature, if completely unrestricted. It was when COM needed to support VB's named arguments that Windows programming really nose-dived. (OTOH: A string mixin can, given the name of a function, tell you what the names of all of it's default arguments are (as well as what their default values are). I can in fact write a string mixin implementation of this feature; it's perfectly feasible. But is the concept actually a good idea?)
Dec 05 2007
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Don Clugston:
 Named arguments are potentially a disastrous feature, if completely
unrestricted.
They are quite handy and useful when used wisely, but they require care, you don't have to use them too much otherwise you risk doing a mess (this is true for many things in Python. Python is supposed to be a language for almost-newbies, but it contains many things that must be used with discipline, to avoid creating a tangled mess instead of a program. In that regard I think Ruby is even worse than Python. I think Java helps you keep the program tidy and clean even if you have less self-discipline, because it has more built-in 'bondage', almost as Ada. At the moment D seems between Python and Java in that regard. Often the bigger the log10(line_count) is, the higher the discipline you need to write the program with, imposed by the language or self-imposed. D's macros will make D a more flexible too, but sharper and more dangerous too, so will need more self-discipline to use it. Something similar is true in Lisp too. Scheme has more hygenic macros to give some restraints to the semantic and decrease bugs). Bye, bearophile
Dec 05 2007
prev sibling parent reply renoX <renosky free.fr> writes:
Don Clugston Wrote:
 Artyom Shalkhakov wrote:
 Hello everyone.
 
 I suggest adding a new syntax for function parameter passing. To illustrate:
 
 void foo( int a, float b ) {
     // some code
 }
 
 void main() {
     foo( 1, 2.5f ); // classic
     foo( b : 2.5f, a : -3 ); // sort of struct initializer
 }
 
 Since named arguments can be passed in any order, they can be especially
useful when a function has more than one parameter with a default value.
 
 This concept could be applied to template instantiation as well.
 
 -Artyom Shalkhakov
(Genuine question, not a flame): To play devil's advocate for a moment: doesn't a long parameter list or lots of default arguments indicate a poor design?
A long list of parameter is not needed in order to have parameter passing par name useful: some compilers have added specific checks for memset (only 3 arguments) because quite a few people made an error in the order of parameters..
 Essentially, the name of the argument becomes part of the API. Why isn't 
 function and object name good enough?
I could ask the opposite question: why should we restrict the API to the function and object name instead of using the full data that we have? To answer your question: passing parameter by name increase the readability of the source, reduce the number of mistake when writing the code (and with a good IDE the number of character to type would be the same).
 Named arguments are potentially a disastrous feature, if completely 
 unrestricted. It was when COM needed to support VB's named arguments that 
 Windows programming really nose-dived.
Could you explain this point? (I know nothing about COM).
 (OTOH: A string mixin can, given the name of a function, tell you what the
names 
 of all of it's default arguments are (as well as what their default values
are).
 I can in fact write a string mixin implementation of this feature; it's 
 perfectly feasible. But is the concept actually a good idea?)
Note that passing parameter by name is only useful if programmers doesn't have to jump through hoops to do it, otherwise nobody will use it. renoX
Dec 05 2007
next sibling parent reply Don Clugston <dac nospam.com.au> writes:
renoX wrote:
 Don Clugston Wrote:
 Artyom Shalkhakov wrote:
 Hello everyone.

 I suggest adding a new syntax for function parameter passing. To illustrate:

 void foo( int a, float b ) {
     // some code
 }

 void main() {
     foo( 1, 2.5f ); // classic
     foo( b : 2.5f, a : -3 ); // sort of struct initializer
 }

 Since named arguments can be passed in any order, they can be especially
useful when a function has more than one parameter with a default value.

 This concept could be applied to template instantiation as well.

 -Artyom Shalkhakov
(Genuine question, not a flame): To play devil's advocate for a moment: doesn't a long parameter list or lots of default arguments indicate a poor design?
A long list of parameter is not needed in order to have parameter passing par name useful: some compilers have added specific checks for memset (only 3 arguments) because quite a few people made an error in the order of parameters..
 
 
 Essentially, the name of the argument becomes part of the API. Why isn't 
 function and object name good enough?
I could ask the opposite question: why should we restrict the API to the function and object name instead of using the full data that we have?
Because it's simpler, and there's an enormous body of code (C, C++ for example) which demonstrates a language can get by perfectly well without it; Is the extra cost worth the benefit?
 To answer your question: passing parameter by name increase the readability of
the source, reduce the number of mistake when writing the code (and with a good
IDE the number of character to type would be the same).
But it also means that if you change the name of a parameter in a library, user code will break. Certainly, you'd need some special syntax to specify which parameters are part of the API, otherwise you get horribly brittle code. Overload lookup rules could become complicated.
 Named arguments are potentially a disastrous feature, if completely 
 unrestricted. It was when COM needed to support VB's named arguments that 
 Windows programming really nose-dived.
Could you explain this point? (I know nothing about COM).
<flame> VB allows you to call a C++ COM object by giving a list of argument names (as a text array, with whatever stupid VB formats are possible) together with the argument values as VB Variants. Languages like C++ were supposed to support any combination the VB programmer chose to use. A massive complication of COM code, just to support sloppy practice by VB programmers, and even then it was only necessary because the VB interpreter was too lazy to put the parameters in the right order. </flame>
Dec 05 2007
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Don Clugston:
 Because it's simpler, and there's an enormous body of code (C, C++ for
example) 
 which demonstrates a language can get by perfectly well without it;
I think D (and some dynamic languages too) have demonstrated that there are many things C/C++ lack! (but associative arrays and GC will go into C++0x anyway...) Bye, bearophile
Dec 05 2007
next sibling parent guslay <guslay gmail.com> writes:
bearophile Wrote:

 I think D (and some dynamic languages too) have demonstrated that there are
many things C/C++ lack! (but associative arrays and GC will go into C++0x
anyway...)
 
GC seems to have been pushed after c++0x. http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!330.entry
Dec 05 2007
prev sibling parent reply guslay <guslay gmail.com> writes:
bearophile Wrote:

 I think D (and some dynamic languages too) have demonstrated that there are
many things C/C++ lack! (but associative arrays and GC will go into C++0x
anyway...)
 
GC seems to have been pushed after c++0x. http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!330.entry
Dec 05 2007
parent reply bearophile <bearophileHUGS lycos.com> writes:
guslay:
 GC seems to have been pushed after c++0x.
 http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!330.entry
I see, thank you for the link. They are adding features to allow a simpler support of an external GC instead. I think this will keep D "better" for some more time then :-) (I have used quotes because often you can't tell langage X is better than Y because they are better regarding specific purposes). Bye, bearophile
Dec 05 2007
parent renoX <renosky free.fr> writes:
bearophile a écrit :
 guslay:
 GC seems to have been pushed after c++0x. 
 http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!330.entry
 
I see, thank you for the link. They are adding features to allow a simpler support of an external GC instead. I think this will keep D "better" for some more time then :-)
"better" only if D's GC is considered reliable enough for "serious" projects which is debatable currently: having memory leaks in some case due to the GC isn't acceptable IMHO. renoX
 (I have used quotes because
 often you can't tell langage X is better than Y because they are
 better regarding specific purposes).
 
 Bye, bearophile
Dec 05 2007
prev sibling parent renoX <renosky free.fr> writes:
 I could ask the opposite question: why should we restrict the API to 
 the function and object name instead of using the full data that we have?
Because it's simpler, and there's an enormous body of code (C, C++ for example) which demonstrates a language can get by perfectly well without it;
With hacks in the compiler such as the special case for memset I talked about, I don't think that it works 'perfectly well'.
 Is the extra cost worth the benefit?
 
 To answer your question: passing parameter by name increase the 
 readability of the source, reduce the number of mistake when writing 
 the code (and with a good IDE the number of character to type would be 
 the same).
But it also means that if you change the name of a parameter in a library, user code will break. Certainly, you'd need some special syntax to specify which parameters are part of the API, otherwise you get horribly brittle code.
Uh? Why would renaming the parameters of a function happen more frequently than say renaming a function?
 Overload lookup rules could become complicated.
If two function overloaded function have a different set of parameters name, then if you call a function passing a parameter by name then, then either it's a 'common' name and the normal overload rules apply either it's a name which appears in only one function so it's not an overload anymore (if you have two parameters specific to two different function, it's an error) ..
 Named arguments are potentially a disastrous feature, if completely 
 unrestricted. It was when COM needed to support VB's named arguments 
 that Windows programming really nose-dived.
Could you explain this point? (I know nothing about COM).
<flame> VB allows you to call a C++ COM object by giving a list of argument names (as a text array, with whatever stupid VB formats are possible) together with the argument values as VB Variants. Languages like C++ were supposed to support any combination the VB programmer chose to use. A massive complication of COM code, just to support sloppy practice by VB programmers, and even then it was only necessary because the VB interpreter was too lazy to put the parameters in the right order. </flame>
Interesting. Regards, renoX
Dec 05 2007
prev sibling next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On Dec 5, 2007 1:48 PM, renoX <renosky free.fr> wrote:
 I could ask the opposite question: why should we restrict the API to the
function and object name instead of using the full data that we have?
I often write constructor functions which look something like this this(int x_, int y_, int z_) { x = x_; y = y_; z = z_; } If parameter names were part of the API, then anyone calling my code would have to refer to those constructor parameters as x_, y_ and z_, complete with trailing underscores Of course, I could go back and change all my code to this(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } but that would be a lot of code to change, and it might break calling code!
 To answer your question: passing parameter by name increase the readability of
the source, reduce the number of mistake when writing the code (and with a good
IDE the number of character to type would be the same).


 Named arguments are potentially a disastrous feature, if completely
 unrestricted. It was when COM needed to support VB's named arguments that
 Windows programming really nose-dived.
Could you explain this point? (I know nothing about COM).
 (OTOH: A string mixin can, given the name of a function, tell you what the
names
 of all of it's default arguments are (as well as what their default values
are).
 I can in fact write a string mixin implementation of this feature; it's
 perfectly feasible. But is the concept actually a good idea?)
Note that passing parameter by name is only useful if programmers doesn't have to jump through hoops to do it, otherwise nobody will use it. renoX
Dec 05 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On Dec 5, 2007 1:48 PM, renoX <renosky free.fr> wrote:
 I could ask the opposite question: why should we restrict the API to the
function and object name instead of using the full data that we have?
I often write constructor functions which look something like this this(int x_, int y_, int z_) { x = x_; y = y_; z = z_; } If parameter names were part of the API, then anyone calling my code would have to refer to those constructor parameters as x_, y_ and z_, complete with trailing underscores Of course, I could go back and change all my code to this(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } but that would be a lot of code to change, and it might break calling code!
That's why any named parameter proposal is going to have to flag the named parameters somehow. Non-flagged parameters will continue to behave as always. --bb
Dec 05 2007
parent reply Leandro Lucarella <llucax gmail.com> writes:
Bill Baxter, el  6 de diciembre a las 16:58 me escribiste:
 Janice Caron wrote:
On Dec 5, 2007 1:48 PM, renoX <renosky free.fr> wrote:
I could ask the opposite question: why should we restrict the API to the
function and 
object name instead of using the full data that we have?
I often write constructor functions which look something like this this(int x_, int y_, int z_) { x = x_; y = y_; z = z_; } If parameter names were part of the API, then anyone calling my code would have to refer to those constructor parameters as x_, y_ and z_, complete with trailing underscores Of course, I could go back and change all my code to this(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } but that would be a lot of code to change, and it might break calling code!
That's why any named parameter proposal is going to have to flag the named parameters somehow. Non-flagged parameters will continue to behave as always.
I don't see what's the big problem with named parameters being part of the API (when, by convention, you are told so). This is widely used on Python and works just great and it's damn useful. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- A can of diet coke will float in water While a can of regular coke will sink
Dec 06 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Leandro Lucarella wrote:
 Bill Baxter, el  6 de diciembre a las 16:58 me escribiste:
 Janice Caron wrote:
 On Dec 5, 2007 1:48 PM, renoX <renosky free.fr> wrote:
 I could ask the opposite question: why should we restrict the API to the
function and 
 object name instead of using the full data that we have?
I often write constructor functions which look something like this this(int x_, int y_, int z_) { x = x_; y = y_; z = z_; } If parameter names were part of the API, then anyone calling my code would have to refer to those constructor parameters as x_, y_ and z_, complete with trailing underscores Of course, I could go back and change all my code to this(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } but that would be a lot of code to change, and it might break calling code!
That's why any named parameter proposal is going to have to flag the named parameters somehow. Non-flagged parameters will continue to behave as always.
I don't see what's the big problem with named parameters being part of the API (when, by convention, you are told so). This is widely used on Python and works just great and it's damn useful.
In Python you cannot overload functions based on argument types. Keyword arguments help to fill the void that leaves. So C++ and D don't need keyword args quite as badly as Python. Also a D implementation probably would lack many of the features of Python's keyword args. I doubt you would be able to do things like passing an AA as a set of keyword arguments. I think in the end this is a feature that would be nice but A) probably needs to be designed as part of the language from the beginning. B) needs to be a pet peeve of the person writing the compiler. --bb
Dec 06 2007
parent bearophile <bearophileHUGS lycos.com> writes:
Bill Baxter:
 Also a D implementation probably would lack many of the features of 
 Python's keyword args.  I doubt you would be able to do things like 
 passing an AA as a set of keyword arguments.
I presume a simpler semantics is enough for D; the * and ** semantic of parameter passing in Python 3.0 is probably a bit too much for D. (And in the future that Python syntax with ** may be implmented too in SkedSkin, that translates a subset of Python to C++. I think the main problem isn't implementing its workings, but managing types: probably those function arguments (those dict values) are all of different type. Python dicts have no problem because it's a dynamically typed language, but D's AA are statically typed. So you may need an AA of Box[string]. Note that IronPython runs on dotnet, that has statically typed AAs, so thy have solved similar problems). Bye, bearophile
Dec 06 2007
prev sibling parent renoX <renosky free.fr> writes:
Janice Caron a écrit :
 On Dec 5, 2007 1:48 PM, renoX <renosky free.fr> wrote:
 I could ask the opposite question: why should we restrict the API to the
function and object name instead of using the full data that we have?
I often write constructor functions which look something like this this(int x_, int y_, int z_) { x = x_; y = y_; z = z_; } If parameter names were part of the API, then anyone calling my code would have to refer to those constructor parameters as x_, y_ and z_, complete with trailing underscores
Would have? No only could: nobody said that passing parameter by name should be mandatory. As for the rest, yes having the possibility to pass parameter by name would mean that programmers will try to find better name for the parameters, but that's a plus if you believe in literate programming..
 Of course, I could go back and change all my code to
     this(int x, int y, int z)
     {
         this.x = x;
         this.y = y;
         this.z = z;
     }
I'm not sure that the trailing underscores would be that hurtful to the users.. Maybe such feature could be advertised 6 month before: "In 6 month, the name of your parameter will become visible to the users, please ensure that your parameters names are well-chosen."
 but that would be a lot of code to change, and it might break calling code!
Somehow Python, Ada manage to have this feature without issue, I've seen plenty of rants against both language but *never* read complaints against Python or Ada "passing parameter by name" feature.. renoX
 
 
 
 
 
 
 
 
 
 
 To answer your question: passing parameter by name increase the readability of
the source, reduce the number of mistake when writing the code (and with a good
IDE the number of character to type would be the same).


 Named arguments are potentially a disastrous feature, if completely
 unrestricted. It was when COM needed to support VB's named arguments that
 Windows programming really nose-dived.
Could you explain this point? (I know nothing about COM).
 (OTOH: A string mixin can, given the name of a function, tell you what the
names
 of all of it's default arguments are (as well as what their default values
are).
 I can in fact write a string mixin implementation of this feature; it's
 perfectly feasible. But is the concept actually a good idea?)
Note that passing parameter by name is only useful if programmers doesn't have to jump through hoops to do it, otherwise nobody will use it. renoX
Dec 06 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
 I often write constructor functions which look something like this
And not just constructors, by the way - any "setter" property function is likely to apply the same convention.
Dec 05 2007
prev sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On Dec 5, 2007 1:48 PM, renoX <renosky free.fr> wrote:
 I could ask the opposite question: why should we restrict the API to the
function and object name instead of using the full data that we have?
Another thought. If the name were part of the API then could one overload functions by parameter name? e.g. void f(int a) { /* do something */ } void f(int b) { /* do something different */ } After all, if the name were part of the API, then they have different APIs. I'm not convinced that this is a good idea. It's also not the only alternative. I have in the past written programs which take parameters of the same underlying type in any order, using only D-as-it-is-now (or C++), and it's not so hard. For example, suppose you want a function that looks like MyDate makeDate(int month, int day, int year) but you think callers might get confused about what order to pass the parameters in (European date order, American date order, YMD date order, whatever...) typedef int Year; typedef int Month; typedef int Day; MyDate makeDate(Year y; Month m, Day d) {/*...*/ } MyDate makeDate(Year y, Day d, Month m) { return MyDate(y,m,d); } MyDate makeDate(Day d, Month m, Year y) { return MyDate(y,m,d); } MyDate makeDate(Month m, Day d, Year y) { return MyDate(y,m,d); } That forces callers to name their arguments, as in: MyDate date = makeDate(cast(Day)11, cast(Month)11, cast(Year)1999); If you wanted, you could also add a "default" function that took ints but required parameters in the right order. And that, basically, is problem solved, as far as I can see.
Dec 06 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On Dec 5, 2007 1:48 PM, renoX <renosky free.fr> wrote:
 I could ask the opposite question: why should we restrict the API to the
function and object name instead of using the full data that we have?
Another thought. If the name were part of the API then could one overload functions by parameter name? e.g. void f(int a) { /* do something */ } void f(int b) { /* do something different */ } After all, if the name were part of the API, then they have different APIs. I'm not convinced that this is a good idea. It's also not the only alternative. I have in the past written programs which take parameters of the same underlying type in any order, using only D-as-it-is-now (or C++), and it's not so hard. For example, suppose you want a function that looks like MyDate makeDate(int month, int day, int year) but you think callers might get confused about what order to pass the parameters in (European date order, American date order, YMD date order, whatever...) typedef int Year; typedef int Month; typedef int Day; MyDate makeDate(Year y; Month m, Day d) {/*...*/ } MyDate makeDate(Year y, Day d, Month m) { return MyDate(y,m,d); } MyDate makeDate(Day d, Month m, Year y) { return MyDate(y,m,d); } MyDate makeDate(Month m, Day d, Year y) { return MyDate(y,m,d); } That forces callers to name their arguments, as in: MyDate date = makeDate(cast(Day)11, cast(Month)11, cast(Year)1999); If you wanted, you could also add a "default" function that took ints but required parameters in the right order. And that, basically, is problem solved, as far as I can see.
Gee that's so clean! Not. You've taken one simple function and turned it into 4 functions plus 3 extra types. It's a workaround at best. --bb
Dec 06 2007
parent "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Thu, 06 Dec 2007 08:58:40 -0000, Bill Baxter  =

<dnewsgroup billbaxter.com> wrote:

 Janice Caron wrote:
 On Dec 5, 2007 1:48 PM, renoX <renosky free.fr> wrote:
 I could ask the opposite question: why should we restrict the API to=
=
 the function and object name instead of using the full data that we =
=
 have?
Another thought. If the name were part of the API then could one overload functions by parameter name? e.g. void f(int a) { /* do something */ } void f(int b) { /* do something different */ } After all, if the name were part of the API, then they have differen=
t =
 APIs.
  I'm not convinced that this is a good idea. It's also not the only
 alternative. I have in the past written programs which take parameter=
s
 of the same underlying type in any order, using only D-as-it-is-now
 (or C++), and it's not so hard. For example, suppose you want a
 function that looks like
      MyDate makeDate(int month, int day, int year)
  but you think callers might get confused about what order to pass th=
e
 parameters in (European date order, American date order, YMD date
 order, whatever...)
      typedef int Year;
     typedef int Month;
     typedef int Day;
      MyDate makeDate(Year y; Month m, Day d) {/*...*/ }
     MyDate makeDate(Year y, Day d, Month m) { return MyDate(y,m,d); }=
     MyDate makeDate(Day d, Month m, Year y) { return MyDate(y,m,d); }=
     MyDate makeDate(Month m, Day d, Year y) { return MyDate(y,m,d); }=
  That forces callers to name their arguments, as in:
      MyDate date =3D makeDate(cast(Day)11, cast(Month)11, cast(Year)1=
999);
  If you wanted, you could also add a "default" function that took int=
s
 but required parameters in the right order.
  And that, basically, is problem solved, as far as I can see.
Gee that's so clean! Not. You've taken one simple function and turned it into 4 functions plus 3=
=
 extra types.
 It's a workaround at best.

 --bb
That is a bad example of when (not) to use named parameters. A better on= e = is: typedef double Radions; typedef double Degrees; double sin(Degrees angleInDegrees); double sin(Radions angleInRadians); I think this is the classic example used to justify named parameters in = = Fortran-90. The typedef trick doesn't always work. You can use const for memset memset(void* dest, const void* source, int value); but not for file copy: void copyFile(string source, string dest); Here source and dest are easily confusee leading to errors hard to pick = up = at runtime. It would be nice if you could switch on an extra compiler warning that = forces you to use the parameter names to disambiguiate. Some would argue that an alternative more OO solution would be: File sourceFile(source); sourceFile.copyTo(dest); This kind of thing will be even easier when you can extend classes using= = any function whose first argument is the right type for 'this'. Though there is a = danger of serious encapsulation breakage there. Regards, Bruce.
Dec 06 2007