www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Private default function arguments

reply bearophile <bearophileHUGS lycos.com> writes:
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
next sibling parent reply Clemens <eriatarka84 gmail.com> writes:
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,
 bearophile
Why not this? void foo(int x) { void fooImpl(int x, int depth); { // ... } fooImpl(x, 0); }
Jan 15 2010
next sibling parent Clemens <eriatarka84 gmail.com> writes:
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
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
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
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
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
prev sibling parent reply retard <re tard.com.invalid> writes:
Fri, 15 Jan 2010 04:38:19 -0500, bearophile wrote:

 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:
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.
 The compiler probably takes care of always optimize the extra function
 call away.
Of course, that's a trivial optimization.
Jan 15 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
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
parent reply retard <re tard.com.invalid> writes:
Fri, 15 Jan 2010 07:10:00 -0500, bearophile wrote:

 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.
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, me
Jan 15 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
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
parent reply Clemens <eriatarka84 gmail.com> writes:
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
parent bearophile <bearophileHUGS lycos.com> writes:
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
prev sibling next sibling parent reply Daniel Murphy <yebbliesnospam gmail.com> writes:
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,
 bearophile
You 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
parent bearophile <bearophileHUGS lycos.com> writes:
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
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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,
 bearophile
There 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
prev sibling next sibling parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
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,
 bearophile
I 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
parent "Nick Sabalausky" <a a.a> writes:
"Jesse Phillips" <jessekphillips+D gmail.com> wrote in message 
news:hiqfel$1i3s$1 digitalmars.com...
 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,
 bearophile
I don't think this gains very much and brings about the question about what use is: int foo4(int x, package int depth=0) {...}
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).
Jan 15 2010
prev sibling next sibling parent BCS <none anon.com> writes:
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
prev sibling parent reply Robert Clipsham <robert octarineparrot.com> writes:
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
parent reply =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= <jeberger free.fr> writes:
Robert Clipsham wrote:
 On 15/01/10 08:25, bearophile wrote:
 int 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 ); } ----
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.fr
Jan 16 2010
parent Robert Clipsham <robert octarineparrot.com> writes:
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).

 		Jerome
Ah, 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