Bypassing const with a union

Era Scarecrow rtcvb32 at yahoo.com
Fri Jun 1 13:24:37 PDT 2012


  While working on the BitArray I've come across an interesting 
dilemma, which is both bad and good. Let's take the following

struct S {
   size_t[] array;
}

  Simple enough, however make a const function, and suddenly you 
can't return a copy of it.

   S copy() const {
     return this; //compile-time error
   }

  Not bad, type system is doing it's job. Let's say I want to 
adjust the pointer as a slice

   S opSlice(int s, int e) { //non-const-able call
     S sl;
     sl.array = this.array[s .. e];
     return sl;
   }

  Good, but if I wanted to return an const item (as above) we have 
an issue. Since I want to change the pointer (but not it's 
contents) as a slice, the const system gets in the way without 
duping it.

   //from const, to const
   const(S) opSlice(int s, int e) const {
     S s = this;  //compile error this.array is const
     s.array = this[s .. e]; //compile error
     return s;
   }

   The item starts as const and ends as const and no data (other 
than maybe the struct which is new) changes; we should be able to 
adjust the pointer if we want. If I use a union I can bypass this.

struct S {
   union {
     size_t[] array;
     size_t[array.sizeof / size_t.sizeof] nonConst; //since it's a 
fixed array
   }

   const(S) opSlice(int s, int e) const {
     S sl;
     sl.nonConst = nonConst; //bypass const!
     sl.array = sl.array[s .. e];
     return sl;
   }
}

  Part of the simpler solutions go away when I try to const a 
struct when cast's have already been declared as with BitArray's 
original design. Meaning I couldn't just do this:

  return const(BitArray) s; //template not found for opCast(T) or 
something

  Would I use const within the cast?

   const(BitArray) opCast(T : BitArray)() { //or something similar?
     return const(BitArray) b; //infinite loop?
   }



  Although this means it could be quite dangerous, used in the 
right way it can also be a good thing. However consider this:

union X {
   string str;
   char[] chr;
}

char[] nonConstString(string inString){
   X x;
   x.str = inString;
   return x.chr; //immutable becomes non-immutable?
}

void bomb() {
   auto ncs = nonConstString("Go Boom!");
   ncs[0] = '!'; //should blow up or seg fault?
   writeln(ncs); //in my own test it silently succeeds
}

  Thinking about it, although this is possible you might still 
allow it but send warnings when the compiler detects it. Reason? 
Const takes effect too soon, sometimes before you can finish 
working on the changes. I've tried moving them to a new 
constructor(s) but keep having issues when the inputs are const 
as the struct assumes it's starting non-const. I think...

  Breaking the const system while your still building/preparing 
the new object should be allowed (as with the slice example) but 
once you pass it out it shouldn't be allowed anymore.


More information about the Digitalmars-d-learn mailing list