Copy Constructor DIP

Jonathan M Davis newsgroup.d at jmdavisprog.com
Tue Jul 10 13:38:33 UTC 2018


On Tuesday, 10 July 2018 06:34:34 MDT Guillaume Piolat via Digitalmars-d 
wrote:
> On Tuesday, 10 July 2018 at 11:58:53 UTC, Jonathan M Davis wrote:
> >> Does it allow to remove the "T.init must always be valid for
> >> structs" rule?
> >
> > Why would it? init is the state of the object before any
> > constructor runs, and quite a few things rely on it. The fact
> > that we've allowed default initialization to be disabled
> > already causes plenty of problems as it is. It's occasionally
> > useful, but it definitely complicates things. D was designed
> > with the idea that every type has an init value.
> >
> > What problem are you trying to solve here?
> >
> > - Jonathan M Davis
>
> None, I was just reacting to
> https://medium.com/@feepingcreature/d-structs-dont-work-for-domain-data-c0
> 9332349f43
>
> Proper D structs almost require having a T.init that is valid,
> and in turn many public members may get to check for internal
> validity before doing things. This is in stark contrast to C++
> where "proper" constructor is guaranteed so you don't check such
> validity.
>
> What is a "correct" T.init for a mutex RAII struct? It is a null
> handle value. It's obviously an invalid value for any purpose,
> but the D wrapper has to be a valid struct.

It's not necessarily expected that all of the functions on T.init are going
to work. It's the stuff like copying it, assigning it, destroying it, etc.
that have to work (and aside from destruction, you can even @disable them if
you need to). Not even toString actually needs to work. It's just that it's
so common for folks to print values that it gets annoying when it doesn't
work. And yes, if T.init does not match the invariant, then you can start
running into problems, though it isn't necessarily fatal. Basically, in that
case, you're forced to disable default initialization and avoid actually
doing much with the init value.

Honestly though, the reason that I think that invariants are terrible has
nothing to do with T.init specifically but with opAssign. The invariant gets
checked before opAssign, and in many cases, this makes sense, but in the
case where you're doing something like void initialization or using emplace
on uninitialized memory, it blows up in your face if the garbage that
happened to be in the struct didn't match the invariant. The same would
happen if T.init does not pass the invariant, but T.init isn't required to
hit the problem. It's the fact that you can't bypass the invariant when
giving the object a new value that's the main problem. If both assignment
and copying worked without checking the invariant, then invariants would be
a _lot_ more useful. Unfortunately, when I argued about this quite a bit
with regards to opAssign several years ago, Walter didn't agree at all. He
thought that it was critical that the invariant be valid when opAssign was
called - and there are cases where that's arguably true - but since it
doesn't work once you try to do fancier stuff like emplace, I'm of the
opinion that invariants are unfortunately a waste of time - even without
getting into the issue of init values.

- Jonathan M Davis





More information about the Digitalmars-d mailing list