Unless I'm missing something, it seems that neither of these are
actually possible.
Consider an object which needs internal state to function.
The obvious answer is to create it in the constructor:
struct Foo(T)
{
T* payload;
this() { payload = cast(T*)malloc(T.sizeof); }
~this() { free(payload); }
void foo() {
// do something with payload that fails if not initialized
}
}
But this is not possible in D, because structs can't have default
constructors.
So one may think, I can use lazy initialization instead:
struct Foo(T)
{
T* _payload;
~this() { if(_payload) free(_payload); }
@property T* payload() const {
if(!_payload)
(cast(Foo!T*)&this).payload = cast(T*)malloc(T.sizeof);
return _payload;
}
void foo() {
T* p = payload();
// do something with payload that fails if not initialized
}
void bar() const {
T* p = payload();
// do something with payload that fails if not initialized
}
}
So in C++, the above would be fine.
Since payload can never be perceived by the caller as
uninitialized, the fact that it "breaks" const is irrelevant.
But you can't do this in D.
If the object is defined at module scope as shared static
immutable, the compiler may put it in a readonly section of the
executable which would cause an access violation upon trying to
initialize it, and there is no way to prevent this from happening.
I'm hoping someone will tell me I'm wrong here, because the only
alternative to the above approaches is to add boilerplate to
_every_ _single_ _function_ that uses the payload in order to
deal with separate cases where it's uninitialized.
Is there really no solution for this?