Const, invariant, strings and "constant data need never be copied"
Janice Caron
caron800 at googlemail.com
Fri Nov 2 15:32:10 PDT 2007
On 11/1/07, Stewart Gordon <smjg_1998 at yahoo.com> wrote:
> In DMD 2.006, the definition of string was changed from const(char)[] to
> invariant(char)[] (and similarly wstring and dstring). This change has no
> doubt broken a fair amount of D 2.x code.
All of my D2 code compiled without change.
> Declaring these with invariant parameters therefore means that it
> is often necessary to .idup a string just to pass it to one of these
> functions.
That's not true. If /all/ strings are invariant, throughout, then
everything works.
> Moreover, if a piece of code manipulates strings with a mixture
> of direct modification and calls to std.string functions, it necessitates
> quite a bit of copying of strings.
No it doesn't, it merely means ensuring that the reference is unique
and then calling assumeUnique().
> void main(string[] a) {
> char[] text = cast(char[]) read(a[1]);
Well that line's wrong for a start. It should be
string text = cast(string)read(a[1]);
There's your problem right there.
> foreach (ref char c; text) {
> if ((c >= 'A' && c <= 'M') || (c >= 'a' && c <= 'm')) {
> c += 13;
> } else if ((c >= 'N' && c <= 'Z') || (c >= 'n' && c <= 'z')) {
> c -= 13;
> }
> }
I believe that should be
bool willChange = false;
foreach(char c;text) if (inPattern["A-Za-z"]) { willChange = true; break }
if (willChange)
{
char[] s = text.dup;
foreach (ref char c; s) {
if ((c >= 'A' && c <= 'M') || (c >= 'a' && c <= 'm')) {
c += 13;
} else if ((c >= 'N' && c <= 'Z') || (c >= 'n' && c <= 'z')) {
c -= 13;
}
text = assumeUnique(s);
}
(Before this release, I would have written
text = cast(string)s;
That still compiles without complaint, but assumeUnique() is better).
The test to see if the string will change is good copy-on-write
behavior. The rest is your code, adapted to how you're supposed to do
things in D2.006. First you dup text, because that string /might/ be
in ROM. Then you make your changes. When you've got what you want, you
use assumeUnique() to turn it back into a string. This does /not/ make
a copy.
> In D 2.x, it's
> necessary to change one line, to something like
>
> text = text.idup.replace("\r\n", "\n").replace("\r", "\n").dup;
I don't think that's right. You just declare text to be string instead
of char[] and those dups become unnecessary.
> There are a few caveats to this example:
> - the .idup is only because std.file.read currently returns a mutable
> void[] - we could actually cast it to an invariant as nothing else is going
> to use it
Not could. Should.
> There are probably plenty
> of more involved examples in which there's more difference than this between
> the 1.x and 2.x code.
If every string function you write obeys the copy-(only)-on-write
protocol, then I don't see that.
> 3. Some concept of const-transparent functions.
I believe that's in the planning stage.
More information about the Digitalmars-d
mailing list