digitalmars.D - Default argument values
- bearophile (20/22) May 20 2010 This page talks about default function argument values in C#4:
- Nick Sabalausky (8/22) May 20 2010 I dunno, a caller might rely on a default value being what it was when t...
- Brad Roberts (7/47) May 20 2010 Most inlining is going to cause exactly the same class of problems, whic...
- Adam Ruppe (16/19) May 20 2010 What I do in code where I want this kind of behaviour is something like ...
- div0 (19/44) May 20 2010 -----BEGIN PGP SIGNED MESSAGE-----
- Nick Sabalausky (6/9) May 20 2010 I often use default args as a shortcut for overloads (where applicable)....
- bearophile (30/42) May 20 2010 In ShedSkin (a kind of Python compiler) I plan to do something like that...
- bearophile (3/6) May 20 2010 In ShedSkin things are more complex, the uint has to be a bitmask, becau...
- Brad Roberts (16/21) May 20 2010 There's a key difference.. runtime optimization.
- bearophile (6/8) May 20 2010 See the future -O7 optimizatione level of LLVM/LDC I have just explained...
- Walter Bright (18/21) May 20 2010 If you're designing a D dll, you have to decide what the interface actua...
- bearophile (9/10) May 20 2010 Because it's untidy, in the source code it looks like the information of...
- Walter Bright (5/20) May 20 2010 I don't agree that your proposal is necessarily right or tidy. D is a co...
- Leandro Lucarella (14/28) May 20 2010 I think default parameters are part of the API, if you change the API, y...
- Alex Makhotin (17/21) May 21 2010 Very bad idea, I would say, to change the interface after it was already...
- bearophile (4/5) May 21 2010 D is a big step forward compared to C.
- Kagamin (2/7) May 21 2010 There's no language at run time, only technologies. And the compiler, be...
- Kagamin (1/1) May 21 2010 The problem you are talking of is actually a miscompilation. Why do you ...
http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/05/18/caveats-of-c-4-0-optional-parameters.aspx Near the end it says:If we change the value of the optional argument from 0 to 1, we have to recompile all calling code for the calling code to get the updated value! For folks shipping assemblies for a living, this means that optional argument values don't version well, as callers have to recompile. When I used to work for a company whose product included a DLL, we avoided optional method arguments for just this reason. It's not a reason not to use optional arguments, but it's important to understand how they work so that you don't run into headaches later.<D too copies the default value at the calling point. Looking at this from the eyes of a Python programmer this looks like a dirty hack. This can be a cause of problems in D dlls too, I am not sure. The related discussion on Reddit: http://www.reddit.com/r/programming/comments/c5st2/caveats_of_c_40_optional_parameters/ Someone has given this answer:Have you looked at Scala's implementation on the JVM? It's very simple. Each default parameter generates a static method with a predictable name (e.g. foo$default$3 for parameter 3 of method foo) that may be called to compute the default value of an unsupplied parameter. With this approach, changing the default value of an existing default-valued parameter means changing the implementation of a static method without changing its signature, so there is no need for callers to be recompiled. Because of JIT inlining, the performanceYou can find more info about this Scala feature here: I copy here how it's implemented:For every parameter with a default argument, a synthetic method which computes the default expression is generated. When a method application uses default arguments, the missing parameters are added to the argument list as calls to the corresponding synthetic methods. def f(a: Int = 1, b: String) // generates a method: def f$default$1 = 1 f(b = "3") // transformed to: f(b = "3", a = f$default$1) A default argument may be an arbitrary expression. Since the scope of a parameter extends over all subsequent parameter lists (and the method body), default expressions can depend on parameters of preceding parameter lists (but not on other parameters in the same parameter list). Note that when using a default value which depends on earlier parameters, the actual arguments are used, not the default arguments. < Bye, bearophile
May 20 2010
"bearophile" <bearophileHUGS lycos.com> wrote in message news:ht47l8$gfj$1 digitalmars.com...http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/05/18/caveats-of-c-4-0-optional-parameters.aspx Near the end it says:I dunno, a caller might rely on a default value being what it was when they had compiled it. Forcing them to get a new version of the library and recompile increases the chance that they're notice that the new value is different, either via a "this has changed" in the docs, or when they run it after recompiling with the new version of the library. Not sure if my argument really holds up or not, but just a thought.If we change the value of the optional argument from 0 to 1, we have to recompile all calling code for the calling code to get the updated value! For folks shipping assemblies for a living, this means that optional argument values don't version well, as callers have to recompile. When I used to work for a company whose product included a DLL, we avoided optional method arguments for just this reason. It's not a reason not to use optional arguments, but it's important to understand how they work so that you don't run into headaches later.<D too copies the default value at the calling point. Looking at this from the eyes of a Python programmer this looks like a dirty hack. This can be a cause of problems in D dlls too, I am not sure.
May 20 2010
Most inlining is going to cause exactly the same class of problems, which nearly every shipping application is going to do. Converting these to helpers functions will result in a tiny little function that will be inlined, so, right back to the same basic problem. Later, Brad On Thu, 20 May 2010, bearophile wrote:http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/05/18/caveats-of-c-4-0-optional-parameters.aspx Near the end it says:If we change the value of the optional argument from 0 to 1, we have to recompile all calling code for the calling code to get the updated value! For folks shipping assemblies for a living, this means that optional argument values don't version well, as callers have to recompile. When I used to work for a company whose product included a DLL, we avoided optional method arguments for just this reason. It's not a reason not to use optional arguments, but it's important to understand how they work so that you don't run into headaches later.<D too copies the default value at the calling point. Looking at this from the eyes of a Python programmer this looks like a dirty hack. This can be a cause of problems in D dlls too, I am not sure. The related discussion on Reddit: http://www.reddit.com/r/programming/comments/c5st2/caveats_of_c_40_optional_parameters/ Someone has given this answer:Have you looked at Scala's implementation on the JVM? It's very simple. Each default parameter generates a static method with a predictable name (e.g. foo$default$3 for parameter 3 of method foo) that may be called to compute the default value of an unsupplied parameter. With this approach, changing the default value of an existing default-valued parameter means changing the implementation of a static method without changing its signature, so there is no need for callers to be recompiled. Because of JIT inlining, the performanceYou can find more info about this Scala feature here: I copy here how it's implemented:For every parameter with a default argument, a synthetic method which computes the default expression is generated. When a method application uses default arguments, the missing parameters are added to the argument list as calls to the corresponding synthetic methods. def f(a: Int = 1, b: String) // generates a method: def f$default$1 = 1 f(b = "3") // transformed to: f(b = "3", a = f$default$1) A default argument may be an arbitrary expression. Since the scope of a parameter extends over all subsequent parameter lists (and the method body), default expressions can depend on parameters of preceding parameter lists (but not on other parameters in the same parameter list). Note that when using a default value which depends on earlier parameters, the actual arguments are used, not the default arguments. < Bye, bearophile
May 20 2010
On 5/20/10, bearophile <bearophileHUGS lycos.com> wrote:A default argument may be an arbitrary expression.What I do in code where I want this kind of behaviour is something like this: void func(Whatever* options = null) { if(options is null) options = Whatever(default blah blah); } (substitute null for any invalid amount for the parameter. I recently did some timezone functions that used int.min as the default offset, meaning load it from the global.) If I want to change the Whatever default, I change it there and it still works out. Nothing fancy required. On 5/20/10, Nick Sabalausky <a a.a> wrote:I dunno, a caller might rely on a default value being what it was when they had compiled it.Eh, if you leave the argument off the list, you're saying "I don't really care what this is", so you shouldn't worry about changes... key word being "shouldn't". I know I've broken this rule before, so having to recompile at least would be nice, like you say.
May 20 2010
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Adam Ruppe wrote:On 5/20/10, bearophile <bearophileHUGS lycos.com> wrote:Yeah, I've gone off default arguments, there is rarely a defensibly good default argument, and you can achieve exactly the same functionality with overloads. Either way of doing them sucks; better just to have a properly documented interface. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iD8DBQFL9an0T9LetA9XoXwRAla5AKCXEizxgvbcNHVWwn+HgRRtukC8RACeJEFc 7wUACeT+f3WGTOLZpBGNcys= =unAD -----END PGP SIGNATURE-----A default argument may be an arbitrary expression.What I do in code where I want this kind of behaviour is something like this: void func(Whatever* options = null) { if(options is null) options = Whatever(default blah blah); } (substitute null for any invalid amount for the parameter. I recently did some timezone functions that used int.min as the default offset, meaning load it from the global.) If I want to change the Whatever default, I change it there and it still works out. Nothing fancy required. On 5/20/10, Nick Sabalausky <a a.a> wrote:I dunno, a caller might rely on a default value being what it was when they had compiled it.Eh, if you leave the argument off the list, you're saying "I don't really care what this is", so you shouldn't worry about changes... key word being "shouldn't". I know I've broken this rule before, so having to recompile at least would be nice, like you say.
May 20 2010
"div0" <div0 users.sourceforge.net> wrote in message news:ht49le$jgu$1 digitalmars.com...Yeah, I've gone off default arguments, there is rarely a defensibly good default argument, and you can achieve exactly the same functionality with overloads.I often use default args as a shortcut for overloads (where applicable). And I've often had cases where default args were useful for getting a good combination of "super-simple interface for typical cases" and "high configurability for when it's actually needed".
May 20 2010
Adam Ruppe:void func(Whatever* options = null) { if(options is null) options = Whatever(default blah blah); } (substitute null for any invalid amount for the parameter. I recently did some timezone functions that used int.min as the default offset, meaning load it from the global.) If I want to change the Whatever default, I change it there and it still works out. Nothing fancy required.In ShedSkin (a kind of Python compiler) I plan to do something like that automatically. The compiler creates a nullable value for each value that has a default, plus the if+assign inside the function. The nullable is done compactly, with an extra uint argument that encodes what arguments are actually given or what ones are not given and need to be initialized inside the function. So if you write code like this: void foo(int x, string s="hello", int y=10) { } void main() { foo(1, "red", 2); foo(3, "green"); foo(4); } It is syntax sugar for: void foo(int x, string s, int y, uint nDefaults) { if (nDefaults >= 1) y = 10; if (nDefaults >= 2) s = "hello"; } void main() { foo(1, "red", 2, 0); foo(3, "green", int.init, 1); foo(4, string.init, int.init, 2); } This is not exactly like the Python semantics, because in Python default arguments are set at function definition time (defining a function is an operation). Even if this can be acceptable for ShedSkin, probably it's not a good solution for a almost-system language as D. ----------------- Brad Roberts:Converting these to helpers functions will result in a tiny little function that will be inlined, so, right back to the same basic problem.<I am not sure, but in Scala they can be virtual functions, so the HotSpot inlines/deinlines them dynamically and as needed to keep the code both fast and safe all the time. Thank you for all the answers, bye, bearophile
May 20 2010
The nullable is done compactly, with an extra uint argument that encodes what arguments are actually given or what ones are not given and need to be initialized inside the function.In ShedSkin things are more complex, the uint has to be a bitmask, because arguments are named and can be specified or not specified in not a fixed order. I have shown an example for the less flexible D calling syntax, where your can't ask for default arguments just in the middle of the list of arguments. Bye, bearophile
May 20 2010
On Thu, 20 May 2010, bearophile wrote:Brad Roberts:There's a key difference.. runtime optimization. Moving the optimizing to runtime allows the code to stay properly isolated in terms of storage and how it's bundled for shipping to end users. Because the default handling can be bundled on the 'right' side of the caller/callee barrier, it eliminates the problem of replacing the implementation with the new default and by optimizing at runtime, eliminates the overhead of the extra function call. A win win.. except for the cost of performing the optimizations at runtime and the vm in general. But that technique can't be done short of runtime optmizing, which c-family languages (such as D) don't do. So, choose your set of problems.. not really a single one that solves them all yet. Later, BradConverting these to helpers functions will result in a tiny little function that will be inlined, so, right back to the same basic problem.<I am not sure, but in Scala they can be virtual functions, so the HotSpot inlines/deinlines them dynamically and as needed to keep the code both fast and safe all the time.
May 20 2010
Brad Roberts:But that technique can't be done short of runtime optmizing, which c-family languages (such as D) don't do.See the future -O7 optimizatione level of LLVM/LDC I have just explained: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.announce&article_id=18420 The future of D optimizations is not set in stone :-) Bye, bearophile
May 20 2010
bearophile wrote:D too copies the default value at the calling point. Looking at this from the eyes of a Python programmer this looks like a dirty hack.I don't see how it could be called a dirty hack.This can be a cause of problems in D dlls too, I am not sure.If you're designing a D dll, you have to decide what the interface actually is. Anything that appears in your .di interface file is part of the interface, and if you change that interface, you have to recompile all code that relies on it. A default argument value is part of the interface. Don't use default argument values if you don't want them to be part of the interface. They are trivially avoided: int foo(int i, int j = 7); becomes: int foo(int i); int foo(int i, int j); and in your implementation: int foo(int i) { return foo(i, y); } Again, *anything* about the interface you expose will force recompilation of everything that uses that interface, if the interface changes in any way. D provides all the features necessary to support common and well understood techniques for implementation hiding and abstraction.
May 20 2010
Walter Bright:I don't see how it could be called a dirty hack.Because it's untidy, in the source code it looks like the information of the default value is located in the function definition, while in truth it is stored elsewhere. This can be more efficient, but it is not tidy, this abstraction can leak a lot, you can see it here: http://d.puremagic.com/issues/show_bug.cgi?id=4028 Maybe this too is related: http://d.puremagic.com/issues/show_bug.cgi?id=3430 I presume this part of the D design will not change (even if a solution for those two bugs need to be found), but a language designer must be able to tell apart what is done for efficiency (putting the information of the default arguments at the calling point) and what's the right and tidy thing to do (putting this information somehow connected to the function itself). Bye, bearophile
May 20 2010
bearophile wrote:Walter Bright:These are both bugs, and not a design fault in having default arguments.I don't see how it could be called a dirty hack.Because it's untidy, in the source code it looks like the information of the default value is located in the function definition, while in truth it is stored elsewhere. This can be more efficient, but it is not tidy, this abstraction can leak a lot, you can see it here: http://d.puremagic.com/issues/show_bug.cgi?id=4028 Maybe this too is related: http://d.puremagic.com/issues/show_bug.cgi?id=3430I presume this part of the D design will not change (even if a solution for those two bugs need to be found), but a language designer must be able to tell apart what is done for efficiency (putting the information of the default arguments at the calling point) and what's the right and tidy thing to do (putting this information somehow connected to the function itself).I don't agree that your proposal is necessarily right or tidy. D is a compile time language, and it would be strange to expect it to behave otherwise. I also don't see recompilation as a problem, as D compiles at an incredible speed.
May 20 2010
bearophile, el 20 de mayo a las 16:56 me escribiste:http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/05/18/caveats-of-c-4-0-optional-parameters.aspx Near the end it says:I think default parameters are part of the API, if you change the API, you have to recompile the client code. The only problem I see is the DLL will still run if it's not recompiled, but that can happen too with other kind of changes (like changes the enum values a function accepts), so this is not a problem present only in default values. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- In Minnesota there's a law That prevents men from having sex with living fishIf we change the value of the optional argument from 0 to 1, we have to recompile all calling code for the calling code to get the updated value! For folks shipping assemblies for a living, this means that optional argument values don't version well, as callers have to recompile. When I used to work for a company whose product included a DLL, we avoided optional method arguments for just this reason. It's not a reason not to use optional arguments, but it's important to understand how they work so that you don't run into headaches later.<
May 20 2010
bearophile wrote:Near the end it says:Very bad idea, I would say, to change the interface after it was already published. Not surprising the new rules break the caller.If we change the value of the optional argument from 0 to 1, we have to recompile all calling code for the calling code to get the updated value! For folks shipping assemblies for a living, this means that optional argument values don't version well, as callers have to recompile. When I used to work for a company whose product included a DLL, we avoided optional method arguments for just this reason. It's not a reason not to use optional arguments, but it's important to understand how they work so that you don't run into headaches later.<I presume this part of the D design will not changeAnd again my point here(not only on this topic specifically) is that the compiler should be programmer's friend, not the opposite. It must be based on the strict specification where such possible problems documented in detail. Ideal solution, IMHO, such inconsistencies must be restricted or forbidden until documented properly. The compiler should give warnings whenever possible and as many as needed to help detect bugs. From my point of view, a good designed language should not, in principle, allow undefined, leading to bugs behavior. All possible issues should be predicted and treated adequately before they even emerge. As I look at D, I do not experience such attitude. -- Alex Makhotin, the founder of BITPROX, http://bitprox.com
May 21 2010
Alex Makhotin:As I look at D, I do not experience such attitude.D is a big step forward compared to C. Bye, bearophile
May 21 2010
Alex Makhotin Wrote:IMHO, such inconsistencies must be restricted or forbidden until documented properly. The compiler should give warnings whenever possible and as many as needed to help detect bugs. From my point of view, a good designed language should not, in principle, allow undefined, leading to bugs behavior.There's no language at run time, only technologies. And the compiler, being a compile-time tool, can't give warnings when the compiled application is run later.
May 21 2010
The problem you are talking of is actually a miscompilation. Why do you expect miscompiled code to work correctly? I can think of other means to miscompile code, so what?
May 21 2010