Burton Radons wrote:
Walter Bright Wrote:
Burton Radons wrote:
That's what we said about strings in 1.0. You modify it, you copy
it, or you tell the user. The gentleman's agreement worked
perfectly and that came without a mess of keywords, without
implicit or explicit restrictions on behaviour, without having to
condition templates.
The one flaw in it was the behavior I consistently saw of "I'm
copying the string just to be sure I own it and nobody else changes
it." D was meant for copy-on-write, which means copy the string
*only* if you change it. No defensive copying. No "just in case"
copying. The gentleman's agreement failed as far as I could tell.
With immutable strings, the gentleman's agreement is enforced.
Am I going to become a broken record on this? Because "invariant
(char) []" is the string type, data that is going to be mutable will
always find its way into that type in order to deal with an API which
WILL use string as its arguments, not writing out "const (char) []".
It gives me no information about the future of the object while
removing the apparent need for the gentleman's agreement. Therefore I
have no way of knowing what the actual pedigree of this string I've
been given has. It may be invariant, it may be mutable.
I want this to be addressed directly. Exactly how am I wrong on this
point? Is it not conceivable that mutable data gets casted to
invariant in this case?
It is conceivable by means of a cast. I've explained that casts can
break any of D's guarantees, so there is nothing new that you can
masquerade a mutable string into an immutable one. If there was a means
to implicitly convert a mutable string into an immutable one, you'd have
a case. But it either looks like you're not understanding something, or
are using a double standard when it comes about casting as applied to
immutability in particular.
There is one point where we are forced to doing something gauche:
assumeUnique. We could have avoided that by introducing a "unique"
notion, but we thought we'd simplify the language by not doing so. So
far the uses of assumeUnique seem to be idiomatic and contained enough
to not be a threat, so it seems to have been a passable engineering
decision.
To recap, if an API takes a string and all you have a char[], DO NOT
CAST IT. Call .idup - better safe than sorry. The API may evolve and
store a reference for later. Case in point: the up-and-coming
std.stdio.File constructor initially was:
this(in char[] filename);
Later on I decided to save the filename for error message reporting and
the such. Now I had two choices:
(1) Leave the signature unchanged and issue an idup:
this.filename = to!string(filename); // issues an idup
(2) Change the signature to
this(string filename);
Now all client code that DID pass a string in the first place (the vast
majority) was safe _and_ efficient. The minority of client code was that
that had a char[] or a const(char)[] at hand. That code did not compile,
so it had to insert a to!string on the caller side.
As has been copiously shown in other languages, the need for
character-level mutable string is rather rare. So most of the time you
will not traffic in char[], but instead you'll have a immutable(char)[]
to start with. This further erodes the legitimacy of your concern.
I have no idea how to make this any more clearer. I explained it so many
times and in so many ways, even I understood it :o).
Andrei