www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Private default arguments?

reply "bearophile" <bearophileHUGS lycos.com> writes:
Often recursive functions need some "bookkeeping" default 
arguments that aren't meant to be used by the user, they are 
meant to be used only by recursive calls:


void radixSort(uint[] items, in uint shiftBits=24) {
     ...
     if (shiftBits > 0) {
         ...
         radixSort(array[...], shiftBits - 8);
     }
}
void main() {
     auto array = new uint[n];
     ...
     array.radixSort();
}



So this call is a bug:

void main() {
     ...
     array.radixSort(26);
}


To avoid bugs and to not expose such private arguments I 
sometimes define an inner function (or a private function in a 
struct/class). Now the only argument of the outer function is 
'items', and no mistakes can happen using radixSort2():


void radixSort2(uint[] items) {
     void radix(in uint shiftBits=24) {
         ...
         if (shiftBits > 0) {
             ...
             radixSort(array[...], shiftBits - 8);
         }
     }
     radix();
}


This has some disadvantages.

An alternative idea (that I maybe I proposed years ago in a 
weaker form) is to introduce 'private' default arguments (they 
must have a default value):


void radixSort3(uint[] items, private in uint shiftBits=24) {
     ...
     if (shiftBits > 0) {
         ...
         radixSort(array[...], shiftBits - 8);
     }
}


The 'private' means that only radixSort3 is allowed to set a 
shiftBits argument value. So this is reported as compilation 
error:

void main() {
     ...
     array.radixSort(26);
}


A more detailed proposal, almost a DEP:
http://d.puremagic.com/issues/show_bug.cgi?id=9229

Is this little feature worth the amount of language complexity 
increase it causes?

Bye,
bearophile
Dec 28 2012
next sibling parent Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
I like the idea. I really don't like having the overhead of inner functions
just for compile-time enforcement.


On Fri, Dec 28, 2012 at 2:58 PM, bearophile <bearophileHUGS lycos.com>wrote:

 Often recursive functions need some "bookkeeping" default arguments that
 aren't meant to be used by the user, they are meant to be used only by
 recursive calls:


 void radixSort(uint[] items, in uint shiftBits=24) {
     ...
     if (shiftBits > 0) {
         ...
         radixSort(array[...], shiftBits - 8);
     }
 }
 void main() {
     auto array = new uint[n];
     ...
     array.radixSort();
 }



 So this call is a bug:

 void main() {
     ...
     array.radixSort(26);
 }


 To avoid bugs and to not expose such private arguments I sometimes define
 an inner function (or a private function in a struct/class). Now the only
 argument of the outer function is 'items', and no mistakes can happen using
 radixSort2():


 void radixSort2(uint[] items) {
     void radix(in uint shiftBits=24) {
         ...
         if (shiftBits > 0) {
             ...
             radixSort(array[...], shiftBits - 8);
         }
     }
     radix();
 }


 This has some disadvantages.

 An alternative idea (that I maybe I proposed years ago in a weaker form)
 is to introduce 'private' default arguments (they must have a default
 value):


 void radixSort3(uint[] items, private in uint shiftBits=24) {
     ...
     if (shiftBits > 0) {
         ...
         radixSort(array[...], shiftBits - 8);
     }
 }


 The 'private' means that only radixSort3 is allowed to set a shiftBits
 argument value. So this is reported as compilation error:

 void main() {
     ...
     array.radixSort(26);
 }


 A more detailed proposal, almost a DEP:
 http://d.puremagic.com/issues/**show_bug.cgi?id=9229<http://d.puremagic.com/issues/show_bug.cgi?id=9229>

 Is this little feature worth the amount of language complexity increase it
 causes?

 Bye,
 bearophile
-- Bye, Gor Gyolchanyan.
Dec 28 2012
prev sibling next sibling parent reply Nick Treleaven <ntrel-public yahoo.co.uk> writes:
On 28/12/2012 10:58, bearophile wrote:
 An alternative idea (that I maybe I proposed years ago in a weaker form)
 is to introduce 'private' default arguments (they must have a default
 value):


 void radixSort3(uint[] items, private in uint shiftBits=24) {
      ...
      if (shiftBits > 0) {
          ...
          radixSort(array[...], shiftBits - 8);
      }
 }
I like the idea, it's intuitive.
 The 'private' means that only radixSort3 is allowed to set a shiftBits
 argument value.
I think the feature is more useful/flexible if private still means module visibility. I realize you would lose the benefit when using radixSort3 from the same module, but then the feature has more potential applications. (Ideally D would have both module-private and local-private qualifiers, but that's another topic). The feature might be useful for things like logging: void log(T...)(T args, private string file = __FILE__, private size_t line = __LINE__); That could allow the compiler to distinguish variadic arguments from non-overridable default arguments (for calls outside private scope). It's also nice to prevent the user accidentally overriding file and line. To allow wrapping log(), another function can be provided, without any default arguments: void logWrapped(string s, string file, size_t line);
Dec 28 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Nick Treleaven:

 The feature might be useful for things like logging:

 void log(T...)(T args, private string file = __FILE__,
 	private size_t line = __LINE__);
I see, and I understand. I find it a little funny that I suggest a feature for recursive functions, and the first proposal for alternative usage is for logging :o) Bye, bearophile
Dec 28 2012
parent reply "monarch_dodra" <monnarchdodra gmail.com> writes:
On Friday, 28 December 2012 at 14:10:01 UTC, bearophile wrote:
 [SNIP]
 bearophile
What's wrong with: //---- void radixSort(uint[] items) { radixSortRecurse(items); } private void radixSortRecurse(uint[] items, in uint shiftBits=24) { ... if (shiftBits > 0) { ... radixSortRecurse(array[...], shiftBits - 8); } } //---- I know I never write recursive functions with a public entry point anyways: You *always* end up with "test only the first time" or "countdown the number of iterations" or some other problem that will force you onto this scheme sooner or later anyways. As mentioned, this also allows module level sharing.
Dec 28 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

 What's wrong with:

 //----
 void radixSort(uint[] items)
 {
      radixSortRecurse(items);
 }


 private void radixSortRecurse(uint[] items, in uint 
 shiftBits=24)
 {
      ...
      if (shiftBits > 0) {
          ...
          radixSortRecurse(array[...], shiftBits - 8);
      }
 }
That's what I do in languages that don't allow nested functions, like ANSI C, etc. It's very similar to defining a static inner function in D. You end with two functions, two names, more code, etc. Bye, bearophile
Dec 28 2012
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Friday, 28 December 2012 at 10:58:59 UTC, bearophile wrote:
 Often recursive functions need some "bookkeeping" default 
 arguments that aren't meant to be used by the user, they are 
 meant to be used only by recursive calls:
What happens when function with private argument is stored in a function pointer? Currently (2.061 beta) if you do so with a function with default argument, you have to supply all default arguments (it seems that some information is lost when making function pointer from function). So, declaring some default argument as private makes function pointer useless: on the one hand, you have to supply all arguments when calling from pointer, on the other hand it is forbidden to supply default private arguments. I don't like a name for this feature because it breaks logic that private is accessible within module. Perhaps a new name? I also against some simple and dummy constraints (like one-path-constructor call restriction) which can be easily avoided and does not really prevent from making mistakes. class A { this(int i) { } this() { int x; // it is rejected // Error: one path skips constructor // Error: return without calling constructor // if (x) // this(1); if (x) // it works __ctor(1); } } void main() { A a = new A; } I think your private argument constraint can be as easily broken: D is a system language and there is no way to prevent it from calling arbitrary code. IMHO it does make sense to apply restrictions which prevent from doing danger things - this reduces space for mistakes, but constraints like you propose and above are not that serious as others.
Dec 28 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Maxim Fomin:

 What happens when function with private argument is stored in a 
 function pointer?
You have to supply all arguments. I've written this in the detailed proposal: http://d.puremagic.com/issues/show_bug.cgi?id=9229
 I don't like a name for this feature because it breaks logic 
 that private is accessible within module. Perhaps a new name?
I understand. I think proposing a new keyword, or a keyword, in infeasible, because all this stuff not important enough :-(
 I think your private argument constraint can be as easily 
 broken:
I am not concerned by ways to force the usage of those private arguments (like taking the address and using it to call the function). It's like the yellow-black plastic strips you see around. They are there to tell you to not go forward, for a real danger or a legal danger, but they don't actually stop you. Thank you, bye, bearophile
Dec 28 2012
parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Friday, 28 December 2012 at 15:42:03 UTC, bearophile wrote:
 Maxim Fomin:

 What happens when function with private argument is stored in 
 a function pointer?
You have to supply all arguments. I've written this in the detailed proposal: http://d.puremagic.com/issues/show_bug.cgi?id=9229
 I don't like a name for this feature because it breaks logic 
 that private is accessible within module. Perhaps a new name?
I understand. I think proposing a new keyword, or a keyword, in infeasible, because all this stuff not important enough :-(
 I think your private argument constraint can be as easily 
 broken:
I am not concerned by ways to force the usage of those private arguments (like taking the address and using it to call the function). It's like the yellow-black plastic strips you see around. They are there to tell you to not go forward, for a real danger or a legal danger, but they don't actually stop you. Thank you, bye, bearophile
I see. Another ideas how to use it: void radixSort3(uint[] items, private in uint shiftBits=24) // original void radixSort3(uint[] items, uint shiftBits is 24) void radixSort3(uint[] items, uint shiftBits=24 const) void radixSort3(uint[] items, static uint shiftBits=24)
Dec 28 2012
prev sibling next sibling parent reply "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Friday, 28 December 2012 at 10:58:59 UTC, bearophile wrote:
 An alternative idea (that I maybe I proposed years ago in a 
 weaker form) is to introduce 'private' default arguments (they 
 must have a default value):

 Is this little feature worth the amount of language complexity 
 increase it causes?
I don't think it is, given how easy it is to work around.
Dec 28 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, December 28, 2012 19:17:45 Peter Alexander wrote:
 On Friday, 28 December 2012 at 10:58:59 UTC, bearophile wrote:
 An alternative idea (that I maybe I proposed years ago in a
 weaker form) is to introduce 'private' default arguments (they
 must have a default value):
 
 Is this little feature worth the amount of language complexity
 increase it causes?
I don't think it is, given how easy it is to work around.
Agreed. All you need to do is create an inner function which holds the majority of the function's body or a private function which does the same (and it can even have exactly the same if you want it to avoiding the need to come up with another name). I really think that this is a non-issue. - Jonathan M Davis
Dec 28 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 I really think that this is a non-issue.
It's not a necessary feature, but it helps make the code more readable, shorter, keeping it safe. I write several recursive functions, and I'd like a way to refer to the function inside the function without using its real name, something like self(), or even __function(). Private default arguments help further the use of recursion. Bye, bearophile
Dec 28 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, December 29, 2012 07:01:42 bearophile wrote:
 Jonathan M Davis:
 I really think that this is a non-issue.
It's not a necessary feature, but it helps make the code more readable, shorter, keeping it safe. I write several recursive functions, and I'd like a way to refer to the function inside the function without using its real name, something like self(), or even __function(). Private default arguments help further the use of recursion.
AFAIK, not even functional languages where recursion is what you always do have anything like what you're suggesting. I really don't see it as any real cost to do recursion use the function's name. So, feel free to bring it up as a feature that you'd like, but I really think that it's trying to solve something that really isn't a problem in the first place. And this is coming from someone who used to program in haskell quite a bit. - Jonathan M Davis
Dec 29 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 AFAIK, not even functional languages where recursion is what 
 you always do have anything like what you're suggesting.
 ...
 And this is coming from someone who used to program in haskell
 quite a bit.
The little enhancement request discussed here requires default arguments. Function languages like Haskell don't have default arguments (despite there are some ways to have them http://neilmitchell.blogspot.it/2008/04/optional-parameters-in-haskell.html ), so you can't compare well the two situations. Bye, bearophile
Dec 30 2012
prev sibling parent reply "F i L" <witte2008 gmail.com> writes:
Good idea, but honestly what we really need is a "static foreach"
Dec 28 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
F i L:

 Good idea, but honestly what we really need is a "static 
 foreach"
I opened this time ago, but this is another topic, and it's better to keep threads separate: http://d.puremagic.com/issues/show_bug.cgi?id=4085 Bye, bearophile
Dec 28 2012