An Invariant WTH?

Chad J gamerChad at _spamIsBad_gmail.com
Mon Nov 5 17:17:29 PST 2007


Daniel Keep wrote:
> 
>> The pass-by-ref vs. pass-by-val seems juicy, but I don't think I
>> understand entirely.  How does constness solve this?  Aren't strings
>> ALWAYS referenced to, or are you referring to the reference itself being
>> a value or something referred to?  A simple code snippet demonstrating
>> this would be great (you can refer me to this if it's been done).
> 
> The funny thing is that an invariant array *works* like it's
> pass-by-value, basically by virtue of the fact that no one else can
> change it.
> 
> As an example, you can't do this:
> 
> int a = 1;
> int b = a;
> b += 5;
> assert( a == 6 ); // Nope
> 
> But you *can* do this:
> 
> char[] a = "foo";
> char[] b = a;
> b[] = "bar";
> assert( a == "bar" ); // Yup
> 
> While invariant strings act like 'int' does:
> 
> string a = "foo";
> string b = a;
> //b[] = "bar"; // Doesn't work
> b = "bar";
> assert( a == "bar" ); // Nope
> 
> A practical use of this: in DOM, you can do this:
> 
> char[] name = "tag-name";
> new Element(name);
> 
> The problem is that I don't know who "owns" the string that gets passed
> in.  Currently, for the sake of efficiency, I don't dup strings passed
> in.  However, this means that if anyone even accidentally changes the
> value pointed to by 'name', it can screw up the DOM tree.
> 
> If I use 'string', on the other hand, I can pass them around willy-nilly
> as values.  It's the same as passing around an int and not having to
> worry about the value of the int changing (unless you're using Java in
> which case the value of an int *can* apparently change.)  You can't
> redefine, say, 0 to mean 8.  Yes, they're still really references, but
> they work like values.
> 
> So the ctor would probably become:
> 
> this(char[] tagName)
> {
>     this.tagName = tagName.idup; // Need an immutable copy
> }
> 
> this(string tagName)
> {
>     this.tagName = tagName; // No copy needed
> }
> 
> Incidentally, this also protects me from having people (ie: myself when
> I'm not paying attention) go element.tagName[0] = 'x' or other silly
> crap like that.
> 

I like where that's going.  Thanks for that.

I'm still not convinced that it's worth the increased complexity in the
language, but that doesn't affect me as a programmer so much, which
means I can deal with it.  Now I at least have a design pattern or two
that leverages this constness thing.

>>>> It's all cost-benefit.  I'm seeing a lot of cost with little or dubious
>>>> benefit.  So why should I be convinced that this is the right thing to
>>>> do?  Why should I be willing to write D2.0 code?
>>> If you're happy with D 1.0, then stick with that (no, this isn't a "if u
>>> dont leik it, get lost!" comment.)  If you want to use the other
>>> features of D 2.0, start writing in it and point out where the const
>>> system fails.  The example you gave at the start of this post is, in
>>> fact, a prime case for *having* a const system, since you didn't even
>>> realise you were making a mistake!
>>>
>> Maybe I am stubborn, but that doesn't tell me that D needs a const
>> system.  It tells me that the way string literals are handled is broken
>> and platform dependent.
> 
> It's more like a bug in Windows :P  For instance, this cropped up in
> #d.tango a while ago:
> 
>     char[] tmp = "000";
>     Integer.format(tmp, cast(long) mode, Integer.Style.Octal);
> 
> What no one realised was that this piece of code actually *redefines*
> the meaning of "000" every time it's run.  Here's a more obvious example:
> 
>     char[] tmp1 = "000";
>     char[] tmp2 = "000";
>     tmp1[1] = '!';
> 
>     writefln("tmp1: %s, tmp2: %s", tmp1, tmp2);
> 
> This outputs "tmp1: 0!0, tmp2: 0!0".  If you're unlucky, this will
> manifest itself in your code as *really weird* errors that are
> impossible to track down.
> 

Yuck.  This is all wrong.  Windows is wrong, and D is too.

I thought that part of the design philosophy in D is that program
correctness comes first, while at the same time giving the programmer
the tools needed to optimize as far as possible.  The way literals are
handled in D1.0 violates that.

In this case the programmer assigns to a variable from a literal.  The 
following things may happen:

               +----------------------------------+
               | action taken by the language     |
               |----------------------------------|
               | dup on assign | ref the literal  |
--------------+---------------+------------------+
string only   |   efficiency  |  everything is   |
read          |     loss*     |      fine        |
--------------+---------------+------------------+
string gets   | everything is | segfault or hard |
modified      |     fine      | to find bugs     |
--------------+---------------+------------------+

* This may very well be a heap allocation if the compiler doesn't know 
what the programmer does with the duplicate.  Escape analysis could 
potentially reduce some cases to a stack allocation with a mem copy. 
"Scope" allocated variables and manual stack allocation would also 
provide means for the programmer to optimize away the inefficiency.  Use 
of static variables can also turn it into a one time startup cost.

I think that the "dup on assign" path would be superior.  I get this 
feeling that the loss in performance would have been moot compared to 
the obscure bugs caused.  This is especially the case if the programmers 
who care about speed apply the trivial optimizations like static and 
scope variables.

Constness does seem to provide a better answer to this, though it'd be 
nice if there was an implicit dup for literals being assigned to 
non-invariant/non-const types, or at least a better error message.

>>> Me?  I'm going to wait until Walter unveils the changes to the const
>>> system.  Arguing about something that's already been declared obsolete
>>> is somewhat pointless :P
>>>
>>>     -- Daniel
>> While I am certainly venting a bit about this, I do want to resolve this
>> somehow.  By "this" I don't mean constness, I mean my personal issues
>> with constness.  Since const doesn't seem to be going away but rather
>> just changing a bit, I am left with one other option: to make me, an
>> angry const-hater, into someone who is not an angry const-hater.
> 
> I don't know if there's much I can say to convince you.  I think this is
> something that, until you *need* it, just seems like a pain-in-the-arse
> imposition.  *I* used to think that languages with const were just
> trying to get in my way, until I started running into situations where
> it actually made my code simpler.
> 
> 	-- Daniel

Well, thanks for trying at least.


More information about the Digitalmars-d-learn mailing list