const?? When and why? This is ugly!

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sat Mar 7 15:19:50 PST 2009


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



More information about the Digitalmars-d mailing list