digitalmars.D - Private default function arguments
- bearophile (36/36) Jan 15 2010 Time ago I have suggested here (and in the Python newsgroup) to have aut...
- Clemens (10/58) Jan 15 2010 Why not this?
- Clemens (2/14) Jan 15 2010 Ah, and I guess you should make fooImpl static if you don't intend to ac...
- bearophile (18/27) Jan 15 2010 OK, I'll use a static nested function then, it's not as clean as adding ...
- bearophile (6/10) Jan 15 2010 It's not as clean indeed, there's a little bug there! Fixed:
- retard (7/24) Jan 15 2010 I don't know what's your definition of clean, but you're twisting the
- bearophile (4/5) Jan 15 2010 Yes, I agree, adding "private" to recursive function attributes is a cut...
- retard (8/15) Jan 15 2010 Beats? It has serious effects on various parts of the language.
- bearophile (9/14) Jan 15 2010 D uses ddoc, as basic solution for this.
- Clemens (2/3) Jan 15 2010 What problems does the static inner function idiom create? It's clean, s...
- bearophile (7/8) Jan 15 2010 Clean: requiring 3-4 extra lines of code and a second name (for the inne...
- Daniel Murphy (9/57) Jan 15 2010 You could accomplish something similar by using a private type as the se...
- bearophile (4/11) Jan 15 2010 It looks like giving error messages if it's located in another module. A...
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (15/63) Jan 15 2010 There is another way that is idiomatic since C:
- Jesse Phillips (13/30) Jan 15 2010 I don't think this gains very much and brings about the question about w...
- Nick Sabalausky (23/46) Jan 15 2010 Another question it brings up: What about this?
- BCS (5/24) Jan 15 2010 My method of choice is:
- Robert Clipsham (12/23) Jan 16 2010 Does this not achieve the same effect? (OK, the syntax is a bit more
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (9/34) Jan 16 2010 Two words: stack overflow. Even if you fix your function to avoid
- Robert Clipsham (6/10) Jan 16 2010 Ah, thanks :)
Time ago I have suggested here (and in the Python newsgroup) to have automatically defined inside a function a standard name like __func__ that's an alias of the recursive function name it's contained into, this helps avoid stating the name of the function two or more times (as the this() constructor of D), this keeps the code a little DRYer, so renaming or moving around a recursive function gets a bit simpler and cleaner. Recursive functions have suggested me another little feature (that can not be added to Python because of its design) that I think I've not seen elsewhere. My recursive functions sometimes need to keep a bit of state, for example an integer that keeps the current "depth" of a tree structure that I'm creating or scanning, normally in D I can define the function like this: /// Always use depth=0 at the first call int foo1(int x, int depth=0) { ... foo1(x, depth + 1); ... } The last argument depth must be zero when the function is not called by itself, but I must rely on convention and code comments, because the program can't avoid errors like: void main() { foo1(10, 5); } To be sure to avoid that error I can create a callable struct that keeps depth as an attribute (code not tested): struct foo2 { int depth = 0; int opCall(int x) { ... } } This foo2 may even be a little faster because less data is passed to the function (callable struct) argument. But another possible solution is to have private default function arguments: int foo3(int x, private int depth=0) { ... foo3(x+1); // OK foo3(x, depth + 1); // OK ... } void main() { int r = foo3(5); // OK int r = foo3(5, 1); // Error int r = foo3(5, 0); // Error } Now the programmer is allowed to give/specify the "depth" argument only inside foo() itself :-) So the source code comment of foo1() is converted in foo3() into something that the compiler can enforce at compile-time. Bye, bearophile
Jan 15 2010
bearophile Wrote:Time ago I have suggested here (and in the Python newsgroup) to have automatically defined inside a function a standard name like __func__ that's an alias of the recursive function name it's contained into, this helps avoid stating the name of the function two or more times (as the this() constructor of D), this keeps the code a little DRYer, so renaming or moving around a recursive function gets a bit simpler and cleaner. Recursive functions have suggested me another little feature (that can not be added to Python because of its design) that I think I've not seen elsewhere. My recursive functions sometimes need to keep a bit of state, for example an integer that keeps the current "depth" of a tree structure that I'm creating or scanning, normally in D I can define the function like this: /// Always use depth=0 at the first call int foo1(int x, int depth=0) { ... foo1(x, depth + 1); ... } The last argument depth must be zero when the function is not called by itself, but I must rely on convention and code comments, because the program can't avoid errors like: void main() { foo1(10, 5); } To be sure to avoid that error I can create a callable struct that keeps depth as an attribute (code not tested): struct foo2 { int depth = 0; int opCall(int x) { ... } } This foo2 may even be a little faster because less data is passed to the function (callable struct) argument. But another possible solution is to have private default function arguments: int foo3(int x, private int depth=0) { ... foo3(x+1); // OK foo3(x, depth + 1); // OK ... } void main() { int r = foo3(5); // OK int r = foo3(5, 1); // Error int r = foo3(5, 0); // Error } Now the programmer is allowed to give/specify the "depth" argument only inside foo() itself :-) So the source code comment of foo1() is converted in foo3() into something that the compiler can enforce at compile-time. Bye, bearophileWhy not this? void foo(int x) { void fooImpl(int x, int depth); { // ... } fooImpl(x, 0); }
Jan 15 2010
Clemens Wrote:Why not this? void foo(int x) { void fooImpl(int x, int depth); { // ... } fooImpl(x, 0); }Ah, and I guess you should make fooImpl static if you don't intend to access foo's x parameter directly.
Jan 15 2010
Clemens:void foo(int x) { void fooImpl(int x, int depth); { // ... } fooImpl(x, 0); }OK, I'll use a static nested function then, it's not as clean as adding a "private" attribute, but probably there's not enough need to add other features to the language: int foo4(int x) { int foo4inner(int x, depth=0) { ... foo4inner(x, depth + 1); ... } return foo4inner(x); } void main() { int r = foo4(5); // OK int r = foo4(5, 1); // Error int r = foo4(5, 0); // Error } The compiler probably takes care of always optimize the extra function call away. Bye and thank you, bearophile
Jan 15 2010
bearophile:OK, I'll use a static nested function then, it's not as clean as adding a "private" attribute, but probably there's not enough need to add other features to the language: int foo4(int x) { int foo4inner(int x, depth=0) {It's not as clean indeed, there's a little bug there! Fixed: static int foo4inner(int x, depth=0) { Clean semantics is always better to avoid bugs :-) Bye, bearophile
Jan 15 2010
Fri, 15 Jan 2010 04:38:19 -0500, bearophile wrote:Clemens:I don't know what's your definition of clean, but you're twisting the semantics of a mostly clean part of the language. Functions have long traditions and roots in lambda calculus. Default arguments are a small modification on top of that. But the private modifier is something that comes from the object oriented approach.void foo(int x) { void fooImpl(int x, int depth); { // ... } fooImpl(x, 0); }OK, I'll use a static nested function then, it's not as clean as adding a "private" attribute, but probably there's not enough need to add other features to the language:The compiler probably takes care of always optimize the extra function call away.Of course, that's a trivial optimization.
Jan 15 2010
retard:But the private modifier is something that comes from the object oriented approach.<Yes, I agree, adding "private" to recursive function attributes is a cute nice borrowed from the OOP. It beats the other three alternatives I've shown. Bye, bearophile
Jan 15 2010
Fri, 15 Jan 2010 07:10:00 -0500, bearophile wrote:retard:Beats? It has serious effects on various parts of the language. Documentation tools need to be aware of this. Requires compiler patch. You need to educate this to new users etc. Did I already mention it increases the complexity of a language that is already fighting featuritis. Bye, meBut the private modifier is something that comes from the object oriented approach.<Yes, I agree, adding "private" to recursive function attributes is a cute nice borrowed from the OOP. It beats the other three alternatives I've shown.
Jan 15 2010
retard:Beats?Yes, in my opinion it's better than the alternatives. In the end here what I will use in normal code is the basic strategy of using just comments.Documentation tools need to be aware of this.D uses ddoc, as basic solution for this.Requires compiler patch.As any solution that changes the language, yes.You need to educate this to new users etc.I think it's not hard to understand and remember.Did I already mention it increases the complexity of a language that is already fighting featuritis.<But it also simplifies code, makes it a bit safer, avoiding some possible bugs both of the original problem and created by the alternative solutions. In the end I think this feature it's not worth it because it's a solution to a very specific problem (but this is also true for few other features of D2 that I think can be removed). Bye, bearophile
Jan 15 2010
bearophile Wrote:But it also simplifies code, makes it a bit safer, avoiding some possible bugs both of the original problem and created by the alternative solutions.What problems does the static inner function idiom create? It's clean, safe, performant, works with the current language and compiler, and has long precedent in other languages supporting nested functions. Lisp and Scheme do this all the time.
Jan 15 2010
Clemens:What problems does the static inner function idiom create? It's clean, safe, performant,<Clean: requiring 3-4 extra lines of code and a second name (for the inner function) is less clean. Generally it's better to minimize the number of names that you need to invent in a program. Safe: it requires more code than just a single "private", so there's a little more chance of bugs: if you take a look at the code I've written in one of the last posts you can see I've forgotten to add "static". Performant: the performance is probably the same if compiled with LDC, but there are two functions, one function call to remove/inline, while the "private" requires no extra work to the optimizer. Idiomatic/documentation: adding "private" in that way you state clearly the purpose of what you are doing, and this can be understood by documentation generator software and IDEs too, while the idiom of a nested static function called inside the outer is less explicit. The semantics is about the same, but the first version shows the purpose directly. Bye, bearophile
Jan 15 2010
bearophile Wrote:Time ago I have suggested here (and in the Python newsgroup) to have automatically defined inside a function a standard name like __func__ that's an alias of the recursive function name it's contained into, this helps avoid stating the name of the function two or more times (as the this() constructor of D), this keeps the code a little DRYer, so renaming or moving around a recursive function gets a bit simpler and cleaner. Recursive functions have suggested me another little feature (that can not be added to Python because of its design) that I think I've not seen elsewhere. My recursive functions sometimes need to keep a bit of state, for example an integer that keeps the current "depth" of a tree structure that I'm creating or scanning, normally in D I can define the function like this: /// Always use depth=0 at the first call int foo1(int x, int depth=0) { ... foo1(x, depth + 1); ... } The last argument depth must be zero when the function is not called by itself, but I must rely on convention and code comments, because the program can't avoid errors like: void main() { foo1(10, 5); } To be sure to avoid that error I can create a callable struct that keeps depth as an attribute (code not tested): struct foo2 { int depth = 0; int opCall(int x) { ... } } This foo2 may even be a little faster because less data is passed to the function (callable struct) argument. But another possible solution is to have private default function arguments: int foo3(int x, private int depth=0) { ... foo3(x+1); // OK foo3(x, depth + 1); // OK ... } void main() { int r = foo3(5); // OK int r = foo3(5, 1); // Error int r = foo3(5, 0); // Error } Now the programmer is allowed to give/specify the "depth" argument only inside foo() itself :-) So the source code comment of foo1() is converted in foo3() into something that the compiler can enforce at compile-time. Bye, bearophileYou could accomplish something similar by using a private type as the second parameter. eg private struct privateint { int i; alias i this; }; void foo(int x, privateint y = privateint(0)) { ... } It's ugly, but should give reasonable error messages.
Jan 15 2010
Daniel Murphy:private struct privateint { int i; alias i this; }; void foo(int x, privateint y = privateint(0)) { ... } It's ugly, but should give reasonable error messages.It looks like giving error messages if it's located in another module. And I agree, it's ugly. In real code for this problem I'll keep using the first solution, that is rely on convention and code comments (the static nested function approach too is too much hairy). Bye, bearophile
Jan 15 2010
bearophile wrote:Time ago I have suggested here (and in the Python newsgroup) to have automatically defined inside a function a standard name like __func__ that's an alias of the recursive function name it's contained into, this helps avoid stating the name of the function two or more times (as the this() constructor of D), this keeps the code a little DRYer, so renaming or moving around a recursive function gets a bit simpler and cleaner. Recursive functions have suggested me another little feature (that can not be added to Python because of its design) that I think I've not seen elsewhere. My recursive functions sometimes need to keep a bit of state, for example an integer that keeps the current "depth" of a tree structure that I'm creating or scanning, normally in D I can define the function like this: /// Always use depth=0 at the first call int foo1(int x, int depth=0) { ... foo1(x, depth + 1); ... } The last argument depth must be zero when the function is not called by itself, but I must rely on convention and code comments, because the program can't avoid errors like: void main() { foo1(10, 5); } To be sure to avoid that error I can create a callable struct that keeps depth as an attribute (code not tested): struct foo2 { int depth = 0; int opCall(int x) { ... } } This foo2 may even be a little faster because less data is passed to the function (callable struct) argument. But another possible solution is to have private default function arguments: int foo3(int x, private int depth=0) { ... foo3(x+1); // OK foo3(x, depth + 1); // OK ... } void main() { int r = foo3(5); // OK int r = foo3(5, 1); // Error int r = foo3(5, 0); // Error } Now the programmer is allowed to give/specify the "depth" argument only inside foo() itself :-) So the source code comment of foo1() is converted in foo3() into something that the compiler can enforce at compile-time. Bye, bearophileThere is another way that is idiomatic since C: private void foo4_R(int x, int depth) { // ... foo4_R(x+1, 0); // OK foo4_R(x, depth + 1); // OK // ... } void foo4(int x) { foo4_R(x, 0); } Of course in C, the _R version would be file-local (i.e. static), instead of 'private'. And in C++, it would be in the anonymous namespace. Ali
Jan 15 2010
bearophile Wrote:int foo3(int x, private int depth=0) { ... foo3(x+1); // OK foo3(x, depth + 1); // OK ... } void main() { int r = foo3(5); // OK int r = foo3(5, 1); // Error int r = foo3(5, 0); // Error } Now the programmer is allowed to give/specify the "depth" argument only inside foo() itself :-) So the source code comment of foo1() is converted in foo3() into something that the compiler can enforce at compile-time. Bye, bearophileI don't think this gains very much and brings about the question about what use is: int foo4(int x, package int depth=0) {...} Sure this could be invalid but it is more consistent if private is allowed. But I think that you'll find many people will just do it like this even with that feature: public int bar(int x) { bar(x, 0); } private int bar(int x, int depth) { ... } Documentation: you don't document the default depth. Yes make comments about it for those programming in that function, but bar(int x) is all that is needed for documentation. Safe: Your complaint about the inner function doesn't seem to be a matter of safety (leaving off static won't crash or cause an incorrect result?). Performance: One of D's goals is to make it easy to do the "right thing." I think performance can be part of this. Your complaint about static does fit here. Clean: The degree your suggestion cleans up the code is minimal. I'm still trying to figure out what benefit Ruby's 'yield' gives one over passing a delegate to a function. It makes for cleaner code, but it seems to be a very simple concept that comes across as very complicated just because some magic stuff happens.
Jan 15 2010
"Jesse Phillips" <jessekphillips+D gmail.com> wrote in message news:hiqfel$1i3s$1 digitalmars.com...bearophile Wrote:Another question it brings up: What about this? class Foo { void bar(private int x=0) { ... } void whee() { // Allowed? And if not, should the feature be extended // to have a way to allow this while disallowing it outside Foo? bar(17); } } I'm not entirely opposed to the idea, but I think it would still need more thought put into it and would end up being only a minor improvement over just using a private overload. I do think though, that the whole system of access modifiers could use to be re-thought. Something like what someone said about Scala's system would be a good thing to think about (to provide maximum flexibility without making the world of access modifiers more complicated than it already is in D), and also what someone said about adding a "true" private, plus there should be a clean way to de-couple specifications of read-access and write-access (ex, to allow read-only members without hacking them in with properties).int foo3(int x, private int depth=0) { ... foo3(x+1); // OK foo3(x, depth + 1); // OK ... } void main() { int r = foo3(5); // OK int r = foo3(5, 1); // Error int r = foo3(5, 0); // Error } Now the programmer is allowed to give/specify the "depth" argument only inside foo() itself :-) So the source code comment of foo1() is converted in foo3() into something that the compiler can enforce at compile-time. Bye, bearophileI don't think this gains very much and brings about the question about what use is: int foo4(int x, package int depth=0) {...}
Jan 15 2010
Hello bearophile,My recursive functions sometimes need to keep a bit of state, for example an integer that keeps the current "depth" of a tree structure that I'm creating or scanning, normally in D I can define the function like this: /// Always use depth=0 at the first call int foo1(int x, int depth=0) { ... foo1(x, depth + 1); ... } The last argument depth must be zero when the function is not called by itself, but I must rely on convention and code comments,My method of choice is: private int foo1(int x, int depth) { ... } int foo1(int x) {return foo1(x,0); } Good inlining might even make this exactly the same as your proposal.
Jan 15 2010
On 15/01/10 08:25, bearophile wrote:int foo3(int x, private int depth=0) { ... foo3(x+1); // OK foo3(x, depth + 1); // OK ... } void main() { int r = foo3(5); // OK int r = foo3(5, 1); // Error int r = foo3(5, 0); // Error }Does this not achieve the same effect? (OK, the syntax is a bit more verbose, but it'd do the trick?) ---- int foo3(int x) { static int depth = 0; foo3( x + 1 ); depth++; foo3( x ); } ----
Jan 16 2010
Robert Clipsham wrote:On 15/01/10 08:25, bearophile wrote:Two words: stack overflow. Even if you fix your function to avoid the stack overflow, this would fail in multithread environments (or be too slow if depth is made thread local). Jerome --=20 mailto:jeberger free.fr http://jeberger.free.fr Jabber: jeberger jabber.frint foo3(int x, private int depth=3D0) { ... foo3(x+1); // OK foo3(x, depth + 1); // OK ... } void main() { int r =3D foo3(5); // OK int r =3D foo3(5, 1); // Error int r =3D foo3(5, 0); // Error }=20 Does this not achieve the same effect? (OK, the syntax is a bit more verbose, but it'd do the trick?) =20 ---- int foo3(int x) { static int depth =3D 0; foo3( x + 1 ); depth++; foo3( x ); } ----
Jan 16 2010
On 16/01/10 14:39, "Jérôme M. Berger" wrote:Two words: stack overflow. Even if you fix your function to avoid the stack overflow, this would fail in multithread environments (or be too slow if depth is made thread local). JeromeAh, thanks :) Seems in my simple single threaded, imperative world I don't see these issues, I guess it's time for me to enter the 21st century and start multi-threading ;) Guess I just need a D2 compiler for my platform to give me that push.
Jan 16 2010