| Thread overview | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 07, 2011 Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
This is a recently opened (not by me) enhancement request thread: http://d.puremagic.com/issues/show_bug.cgi?id=6442 It proposes something that I remember was discussed and refused two times in past: to require (but only optionally!) "ref" and "out" at the calling point, as C#4 instead always requires (optionally for COM): void foo(ref int bar) { ... } int i = 0; foo(ref i); // <------- here void foo(out int bar) { ... } int i = 0; foo(out i); // <------- here Jonathan M Davis has then argued that they clutter the code, and that making them optional makes them kind of useless. See the thread for more details. ----------------- After thinking some about it, I have suggested a related but alternative proposal: to ask only for the "out" at the calling point, make it obligatory if you compile with -warning and optional otherwise (for a long time "override" was like this). I think having "out" at the calling point is more useful than "ref". Currently D 2.054 gives no warnings/errors on a program like this (I think the C# compiler gives something here): void foo(out int x) { x = 5; } void main() { int y = 10; foo(y); } The problem here is the initialization of y to 10 always gets ignored. Assigning something to y, *not using y in any way*, and then using it in a "out" function argument call, is in my opinion a code smell. It's wasted code at best, and sometimes it's related to possible semantic bugs. Using "out" at the calling point doesn't fix that code, but helps the programmer to see that the assign of 10 to y is useless, and it's better to remove it: void foo(out int x) { x = 5; } void main() { int y = 10; foo(out y); } In my opinion "ref" arguments don't have the same need of being tagged at the calling point because a function that uses "ref" often reads and writes the argument (otherwise you use "in" or "out"), so in a ref argument assigning something to y before the call is more often meaningful: void foo(ref int x) { x++; } int main() { int y = 10; return foo(y); } Bye, bearophile | ||||
August 07, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | One the main reasons c# has mandatory out and ref at call site is code versioning. If some function took an argument by value but was changed to take if by reference, without annotations compiler would treat this as an error, preventing a potential bug.
So this feature has to be either mandatory or not. Making it optional leads to confusion as Jonathan mentioned.
But it's kinda late to change the language now, with all the code outthere.
On 2011-08-07 23:42:30 +0300, bearophile said:
> This is a recently opened (not by me) enhancement request thread:
> http://d.puremagic.com/issues/show_bug.cgi?id=6442
>
> It proposes something that I remember was discussed and refused two times in past: to require (but only optionally!) "ref" and "out" at the calling point, as C#4 instead always requires (optionally for COM):
>
> void foo(ref int bar) { ... }
> int i = 0;
> foo(ref i); // <------- here
>
> void foo(out int bar) { ... }
> int i = 0;
> foo(out i); // <------- here
>
>
> Jonathan M Davis has then argued that they clutter the code, and that making them optional makes them kind of useless. See the thread for more details.
>
> -----------------
>
> After thinking some about it, I have suggested a related but alternative proposal: to ask only for the "out" at the calling point, make it obligatory if you compile with -warning and optional otherwise (for a long time "override" was like this). I think having "out" at the calling point is more useful than "ref".
>
> Currently D 2.054 gives no warnings/errors on a program like this (I think the C# compiler gives something here):
>
>
> void foo(out int x) {
> x = 5;
> }
> void main() {
> int y = 10;
> foo(y);
> }
>
>
> The problem here is the initialization of y to 10 always gets ignored. Assigning something to y, *not using y in any way*, and then using it in a "out" function argument call, is in my opinion a code smell. It's wasted code at best, and sometimes it's related to possible semantic bugs.
>
> Using "out" at the calling point doesn't fix that code, but helps the programmer to see that the assign of 10 to y is useless, and it's better to remove it:
>
>
> void foo(out int x) {
> x = 5;
> }
> void main() {
> int y = 10;
> foo(out y);
> }
>
>
> In my opinion "ref" arguments don't have the same need of being tagged at the calling point because a function that uses "ref" often reads and writes the argument (otherwise you use "in" or "out"), so in a ref argument assigning something to y before the call is more often meaningful:
>
>
> void foo(ref int x) {
> x++;
> }
> int main() {
> int y = 10;
> return foo(y);
> }
>
> Bye,
> bearophile
| |||
August 07, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Max Klyga | Max Klyga: > So this feature has to be either mandatory or not. Making it optional leads to confusion as Jonathan mentioned. On this, what I have suggested it not the same thing that the original proposal says. In the original proposal the "ref" and "out" are optional. In my alternative proposal if you compile with "-w" you are sure that the compiler will ask you "out" at the calling point too. > But it's kinda late to change the language now, with all the code outthere. It will take some more years to have enough D2 code out there to make a breaking but incremental change like this too much costly for people. (In Bugzilla I have few more little breaking changes that are more important than this "out" thing. And other things will need to be fixed, in "const" etc. Several of them will break D code in ways more costly than requiring to add a "out" in code here and there). Bye, bearophile | |||
August 08, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 2011-08-07 20:42:30 +0000, bearophile <bearophileHUGS@lycos.com> said: > This is a recently opened (not by me) enhancement request thread: > http://d.puremagic.com/issues/show_bug.cgi?id=6442 > > It proposes something that I remember was discussed and refused two times in past: to require (but only optionally!) "ref" and "out" at the calling point, as C#4 instead always requires (optionally for COM): > > void foo(ref int bar) { ... } > int i = 0; > foo(ref i); // <------- here > > void foo(out int bar) { ... } > int i = 0; > foo(out i); // <------- here > > > Jonathan M Davis has then argued that they clutter the code, and that making them optional makes them kind of useless. See the thread for more details. > > ----------------- > > After thinking some about it, I have suggested a related but alternative proposal: to ask only for the "out" at the calling point, make it obligatory if you compile with -warning and optional otherwise (for a long time "override" was like this). I think having "out" at the calling point is more useful than "ref". > > […] I don't find your arguments very enticing, sorry. But I do see *one* solid reason we might want to add 'ref' and 'out', optional or not, at the call site: variadic templates. I recently had to use getopt. You use it like that: bool option; int counter; getopt(args, "option|o", &option, "counter|c", &counter); The problem is that taking addresses of a stack variable is disabled in SafeD, which means getopt doesn't work in SafeD, which puts SafeD in a strange position. It'd work if we used 'ref' parameters. The problem is that getopt is defined like this: void getopt(T...)(ref string[] args, T opts); Using a type tuple makes it impossible to have 'ref's where they need to be, hence the use of pointers. Type tuples could be made support propagating the type including the 'ref' or 'out' storage class applied on them, which would allow you to write this: getopt!(string, ref bool, string, ref int)(args, "option|o", option, "counter|c", counter); But that doesn't work with type deduction. It could work however if you allowed specifying the 'ref' as part of the argument list: getopt(args, "option|o", ref option, "counter|c", ref counter); I'd prefer if we had a solution that doesn't require you to write 'ref' at the call site, but I haven't found any. Ideas? -- Michel Fortin michel.fortin@michelf.com http://michelf.com/ | |||
August 08, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | Michel Fortin wrote:
> On 2011-08-07 20:42:30 +0000, bearophile <bearophileHUGS@lycos.com> said:
>
>> This is a recently opened (not by me) enhancement request thread: http://d.puremagic.com/issues/show_bug.cgi?id=6442
>>
>> It proposes something that I remember was discussed and refused two times in past: to require (but only optionally!) "ref" and "out" at the calling point, as C#4 instead always requires (optionally for COM):
>>
>> void foo(ref int bar) { ... }
>> int i = 0;
>> foo(ref i); // <------- here
>>
>> void foo(out int bar) { ... }
>> int i = 0;
>> foo(out i); // <------- here
>>
>>
>> Jonathan M Davis has then argued that they clutter the code, and that making them optional makes them kind of useless. See the thread for more details.
>>
>> -----------------
>>
>> After thinking some about it, I have suggested a related but alternative proposal: to ask only for the "out" at the calling point, make it obligatory if you compile with -warning and optional otherwise (for a long time "override" was like this). I think having "out" at the calling point is more useful than "ref".
>>
>> […]
>
> I don't find your arguments very enticing, sorry. But I do see *one* solid reason we might want to add 'ref' and 'out', optional or not, at the call site: variadic templates.
>
> I recently had to use getopt. You use it like that:
>
> bool option;
> int counter;
>
> getopt(args,
> "option|o", &option,
> "counter|c", &counter);
>
> The problem is that taking addresses of a stack variable is disabled in SafeD, which means getopt doesn't work in SafeD, which puts SafeD in a strange position.
>
> It'd work if we used 'ref' parameters. The problem is that getopt is defined like this:
>
> void getopt(T...)(ref string[] args, T opts);
>
> Using a type tuple makes it impossible to have 'ref's where they need to be, hence the use of pointers.
>
> Type tuples could be made support propagating the type including the 'ref' or 'out' storage class applied on them, which would allow you to write this:
>
> getopt!(string, ref bool, string, ref int)(args,
> "option|o", option,
> "counter|c", counter);
>
> But that doesn't work with type deduction. It could work however if you allowed specifying the 'ref' as part of the argument list:
>
> getopt(args,
> "option|o", ref option,
> "counter|c", ref counter);
>
> I'd prefer if we had a solution that doesn't require you to write 'ref' at the call site, but I haven't found any. Ideas?
>
>
> --
> Michel Fortin
> michel.fortin@michelf.com
> http://michelf.com/
void getopt(T...)(ref string[] args, ref T opts);
Would work afaik (but all the flag names would be passed by ref too). std.stdio.readf has the same issue.
The general problem is that type deduction does not currently work too well with implicit conversions (that is also the reason why most string algorithms in Phobos don't work with immutable strings)
I can see a possible solution to the problem: At definition side, it should be possible to manually influence type and storage class deduction.
But I cannot think of syntax for this that wouldn't look awkward. Any ideas?
| |||
August 08, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile wrote:
> Max Klyga:
>
>> So this feature has to be either mandatory or not. Making it optional leads to confusion as Jonathan mentioned.
>
> On this, what I have suggested it not the same thing that the original proposal says. In the original proposal the "ref" and "out" are optional. In my alternative proposal if you compile with "-w" you are sure that the compiler will ask you "out" at the calling point too.
Please bury forever the idea that "mandatory when compiled with -w" has any practical difference from "mandatory".
| |||
August 08, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | Michel Fortin Wrote:
> I recently had to use getopt. You use it like that:
>
> bool option;
> int counter;
>
> getopt(args,
> "option|o", &option,
> "counter|c", &counter);
>
> The problem is that taking addresses of a stack variable is disabled in SafeD, which means getopt doesn't work in SafeD, which puts SafeD in a strange position.
const opts = getopt(args);
const option = opts.get!bool("option|o");
const counter = opts.get!int("counter|c"); // also reusable
| |||
August 08, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile Wrote:
> This is a recently opened (not by me) enhancement request thread: http://d.puremagic.com/issues/show_bug.cgi?id=6442
D is the language to save keystrokes. This proposal is plain invalid.
| |||
August 08, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Kagamin | Though I think, `main` arguments should eliminated altogether and be accessed statically. const ReusableOpts opts = getopts(); const string[] args = mainArgs; // @property: parse args on demand, remove the code from startup. | |||
August 08, 2011 Re: Tagging of arguments ref/out, or just out | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On Aug 9, 11 02:32, Kagamin wrote:
> bearophile Wrote:
>
>> This is a recently opened (not by me) enhancement request thread:
>> http://d.puremagic.com/issues/show_bug.cgi?id=6442
>
> D is the language to save keystrokes. This proposal is plain invalid.
I disagree. If you want to save keystrokes, use Perl.
"D is a multi-paradigm programming language that combines a principled approach with a focus on practicality. In D you get to harness the power and high performance of C and C++ and also the safety and programmer productivity of modern languages such as Ruby and Python. Special attention is given to the needs of quality assurance, documentation, portability, and reliability."
Nowhere mentions saving keystrokes. The proposal is OK, as a mean to provide reliability (where you ensure a variable passed is not modified in opaque because it is pass by 'ref') and documentation at call-site.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply