Immutable member functions and private members

Jonathan M Davis jmdavisProg at gmx.com
Wed Aug 3 01:52:27 PDT 2011


On Wednesday 03 August 2011 10:37:58 simendsjo wrote:
> I have a struct with a private member that is only ever accessed through
> a single property method - even from within the struct.
> As this property fills the value on the first access, it cannot be
> immutable, and as such, none of the many methods accessing this property
> can be immutable methods.
> 
> This is according to specification, but I thought that since the single
> write to the property is done at one, and only one, access point, that
> it would be safe?
> 
> I could fill this value in the constructor, but it's a bit slow, so I'd
> rather do it only if needed.
> 
> And is there any potential performance optimizations done by the
> compiler, or is it "only" for safety?
> Is there a way to hack around this, and more importantly, is it safe to
> do so, or will I open Pandora's box?
> 
> 
> Small example:
> 
> int len(const char[] c) {
>      return c.length;
> }
> 
> struct S {
>      private immutable(char)[] _v;
>      @property immutable(char[]) v() { // Cannot be immutable method
>          if(!_v)
>              _v = "init"; /* or from external function */
>          return _v;
>      }
> 
>      @property int a() { // and so this cannot be immutable method
>          return len(v); /* notice the property function v that might
> modify _v */
>      }
> }
> 
> void main() {
>      S s;
>      s.a;
> }

You're basically looking for logical const - albeit a subset which would be 
much easier to implement were we to implement it (that is, a lazy initialized 
const or immutable member variable). D has no support for logical const. Even 
worse, you're looking for logical immutable (which makes no sense at all 
beyond perhaps lazy initialization and probably doesn't even make sense 
there).

The thing is that immutable methods are pointless unless you make the struct 
immutable (if you want to be able to call them with both a mutable and 
immutable instance of the struct, then you need the functions to be const, not 
immutable). And if you make the struct immutable, the compiler is free to put 
it in read-only memory if it so chooses, at which point setting _anything_ in 
the struct after the constructor has run is likely to blow up. So, even if you 
can get around the issue via casts and get both lazy initialization and 
immutable methods, there's a good chance that it'll blow up at some point (as 
in segfault or worse).

If you were trying to do this with const, you might get away with it (though 
you'd be stepping outside of the type lsystem by casting away const and then 
altering anything - it's undefined behavior). But with immutable, there's no 
way that this is a good idea.

Lazy initialization with const or immutable member variables just is _not_ a 
good idea in D. D provides no type-safe way to do this. You must break the 
type system by casting away const or immutable to even attempt it. 
Convievably, in the case of const, the language could be extended to allow for 
lazy initialization of member variables, but there's no way that it could do 
that with immutable (because the variable could conceivably be put in read-
only memory), and even if it were done, it would likely have to be a D3 
feature. Syntactically, it would probably be something like this:

lazy int v = initFunc();

and then when v was first accessed, initFunc would be called and v set to that 
value. But that could be ugly and inefficient to implement even if it's 
theoretically possible, so I wouldn't bet on anything like that making it into 
the language. Regardless, it wouldn't be until D3. For now, D doesn't support 
any kind of logical const.

http://stackoverflow.com/questions/4219600/logical-const-in-d

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list