www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Unique vs. shared return values

reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
strings provide opportunities for optimization. For example, 
std.string.leftJustify() returns

- either a slice of the entire input string when the field is shorter 
than the string (this is an optimization)

- or a new string when the field is larger than the string

The following program demonstrates this behavior:

import std.string;
import std.array;

void main()
{
     {
         dchar[] input;
         input ~= "hello";

         auto result = leftJustify(input, 3);
         result.front = 'X';
         assert(input.front == 'X');    // <-- input is modified
     }

     {
         dchar[] input;
         input ~= "hello";

         auto result = leftJustify(input, 6);  // note: now 6, not 3
         result.front = 'X';
         assert(input.front == 'h');    // <-- input is NOT modified
     }
}

The issue is whether the caller can be sure about the uniqueness of the 
returned data. Of course the behavior can be documented and the user can 
check the length before calling:

     auto result = (s.length > width) ? s.dup : leftJustify(s, width);

Now the user knows that 'result' is always a copy.

[A side question is whether leftJustify() should throw when the field 
width is shorter than the string. I wouldn't object that behavior. 
Exceptions are great: they remove difficult questions. :)]

Of course this is not a criticism of leftJustify(). I face such 
decisions frequently myself. I am curious about what you think about 
functions that *may* return unique data.

Is that a problem for you? Have you developed guidelines to deal with it?

Thank you,
Ali
Feb 02 2012
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Ali:

 - either a slice of the entire input string when the field is shorter 
 than the string (this is an optimization)
 [A side question is whether leftJustify() should throw when the field 
 width is shorter than the string.
When the field width is shorter than the input string the three justify functions just don't add whitespace. So they are nothrow. Bye, bearophile
Feb 02 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/02/2012 04:31 PM, bearophile wrote:
 Ali:

 - either a slice of the entire input string when the field is shorter
 than the string (this is an optimization)
 [A side question is whether leftJustify() should throw when the field
 width is shorter than the string.
When the field width is shorter than the input string the three
justify functions just don't add whitespace. So they are nothrow.
 Bye,
 bearophile
That side question was more like "may be the justify functions should throw". Otherwise, how is it possible to e.g. left-justify a string in a field shorter than the string? Since the function cannot achieve that task, perhaps it should throw. But that's just a musing... But the main question remains: Some functions sometimes return a reference to passed-in data, sometimes a reference to a newly-allocated data. Is that a good design? Something that I've thought of just now: Maybe a generic copy-on-write reference type should be returned? Looking for opinions and experiences... Ali
Feb 02 2012
parent reply bearophile <bearophileHUGS lycos.com> writes:
Ali:

 That side question was more like "may be the justify functions should 
 throw".
And my answer was: "nope".
 Otherwise, how is it possible to e.g. left-justify a string in a 
 field shorter than the string? Since the function cannot achieve that 
 task, perhaps it should throw. But that's just a musing...
Justify job is not to shorten the input string. So not throwing is needed, and they need to be tagged with "nothrow".
 But the main question remains: Some functions sometimes return a 
 reference to passed-in data, sometimes a reference to a newly-allocated 
 data. Is that a good design? Something that I've thought of just now: 
 Maybe a generic copy-on-write reference type should be returned?
strongly pure functions, pure "new" for arrays, and uniqueness typing, are three solutions. We have the first already, the second is probably coming, and the third is an option for D3. Bye, bearophile
Feb 02 2012
parent "Marco Leise" <Marco.Leise gmx.de> writes:
Am 03.02.2012, 03:31 Uhr, schrieb bearophile <bearophileHUGS lycos.com>:

 Justify job is not to shorten the input string. So not throwing is  
 needed, and they need to be tagged with "nothrow".
"throw on justify" cannot be justified; to 15 characters or any other way
Feb 02 2012
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 02 Feb 2012 18:23:13 -0500, Ali =C3=87ehreli <acehreli yahoo.com=
 wrote:
 strings provide opportunities for optimization. For example,  =
 std.string.leftJustify() returns

 - either a slice of the entire input string when the field is shorter =
=
 than the string (this is an optimization)

 - or a new string when the field is larger than the string
[snip]
 Of course this is not a criticism of leftJustify(). I face such  =
 decisions frequently myself. I am curious about what you think about  =
 functions that *may* return unique data.

 Is that a problem for you? Have you developed guidelines to deal with =
it? When you have a function that may return an alias to it's parameters, or= = it may return new data, there are two very effective ways of dealing wit= h = the possibly non-deterministic result: 1. Treat the resulting data as const explicitly, or force uniqueness by = = dup-ing the result: const result =3D leftJustify(...); auto result =3D = leftJustify(...).dup; 2. Replace the original alias: a =3D leftJustify(a, ...); What you should try to avoid is data that is aliased in two places, and = = modifiable. This is somewhat similar to the non-determinism problem with array = appending. Of course, another very effective approach is to use immutable strings. -Steve
Feb 03 2012