[Issue 1654] Array concatenation should result in mutable or invariant depending on usage

d-bugmail at puremagic.com d-bugmail at puremagic.com
Thu Jan 31 15:49:14 PST 2008


http://d.puremagic.com/issues/show_bug.cgi?id=1654





------- Comment #6 from schveiguy at yahoo.com  2008-01-31 17:49 -------
I still believe the rule works.

The general rule I am extending is, for any basic type(int, char, byte, etc.),
you can copy an invariant version to a mutable version without issue.  i.e.:

invariant(int) x = 1;
int y = x; // works (I think :)

If we imagine that any time you copy a structure or a buffer, instead of doing
a memcpy (which is an implementation detail), you do a copy of each
member/element.

so:

char[5] x;
x[] = "hello";

is equivalent to:

foreach(i, c; "hello")
   x[i] = c;

Which should work because of the first rule (I can copy an invariant(char) to a
char).

Now, for a struct, you can postulate the same thing:

struct S
{
  int x;
}

invariant(S) s1 = cast(invariant)S(1);
S s2;

s2 = s1;

is equivalent to:

s2.x = s1.x;

Which should work because of the first rule.

However, if we think about pointers:

invariant(char)* cp = "hello".ptr;
char * cp2;
cp2 = cp;

this fails because now you have a mutable pointer to invariant data.  Here is
the rule I am trying to exploit.  Because a type has a pointer in it:

struct S
{
  char *cp;
}

invariant(S) s1;
S s2;
s2 = s1;

This is equivalent to:
s2.cp = s1.cp;

which fails the rule above, so the whole thing fails.

With your new syntax, let's look at how it works:

struct Value {
  int * p = null;
  this() { p = new int; }
  ~this() { delete p; }
  this(scope) { p = new int(*p); }
}

invariant(Value) v1;
Value v2;

v2 = v1;
Now, this is possible.  Because instead of using p, we are using *p, which is
of type invariant(int).  invariant(int) can be casted to int implicitly, and so
the rule still works.

I'm not sure if this was intended as a use for your new syntax, but I certainly
still believe that it doesn't break the rules (BTW, I like the idea).

Addressing your point about parting types if they contain pointers are not, I
don't really think of it that way.  What I think of it as is that an invariant
pointer cannot be implicitly copied to a mutable pointer.  If by copying a
type, you have to copy an invariant pointer to a mutable pointer, then the
compile fails.  If you do not have to copy an invariant pointer to a mutable
pointer, then the copy works.  It's just easier to explain as "types that
contain invariant pointers cannot be copied to a non-invariant version of the
type".  The compiler can check this without adding extra runtime information,
so implementation-wise it does not affect the output.  Semantic-wise, it
doesn't break existing code, it just allows operations that should be valid but
aren't under the current scheme.  In fact, I think it's more consistent with
the way builtin types work.

BTW, the same applies to const.

-Steve


-- 



More information about the Digitalmars-d-bugs mailing list