digitalmars.D - Passing function parameters by name
- Artyom Shalkhakov <artyom.shalkhakov gmail.com> Dec 04 2007
- downs <default_357-line yahoo.de> Dec 04 2007
- Robert Fraser <fraserofthenight gmail.com> Dec 04 2007
- Don Clugston <dac nospam.com.au> Dec 05 2007
- bearophile <bearophileHUGS lycos.com> Dec 05 2007
- renoX <renosky free.fr> Dec 05 2007
- Don Clugston <dac nospam.com.au> Dec 05 2007
- bearophile <bearophileHUGS lycos.com> Dec 05 2007
- guslay <guslay gmail.com> Dec 05 2007
- guslay <guslay gmail.com> Dec 05 2007
- bearophile <bearophileHUGS lycos.com> Dec 05 2007
- renoX <renosky free.fr> Dec 05 2007
- renoX <renosky free.fr> Dec 05 2007
- Bill Baxter <dnewsgroup billbaxter.com> Dec 05 2007
- Leandro Lucarella <llucax gmail.com> Dec 06 2007
- Bill Baxter <dnewsgroup billbaxter.com> Dec 06 2007
- bearophile <bearophileHUGS lycos.com> Dec 06 2007
- Bill Baxter <dnewsgroup billbaxter.com> Dec 06 2007
- "Bruce Adams" <tortoise_74 yeah.who.co.uk> Dec 06 2007
- renoX <renosky free.fr> Dec 06 2007
- "Janice Caron" <caron800 googlemail.com> Dec 05 2007
- "Janice Caron" <caron800 googlemail.com> Dec 05 2007
- "Janice Caron" <caron800 googlemail.com> Dec 06 2007
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
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
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
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
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
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
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
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?
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
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
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
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
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
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
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?
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
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
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?
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
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?
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!
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
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
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
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?
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=
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=
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=
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=
If you wanted, you could also add a "default" function that took int=
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
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.. renoXTo 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.
(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?)
renoX
Dec 06 2007
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
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
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









Robert Fraser <fraserofthenight gmail.com> 