assert(obj) is a mystery

Jonathan M Davis jmdavisProg at gmx.com
Wed Nov 9 17:12:51 PST 2011


On Wednesday, November 09, 2011 16:36 Davidson Corry wrote:
> On 11/9/2011 9:35 AM, Jonathan M Davis wrote:
> > On Wednesday, November 09, 2011 05:39 Alex Rønne Petersen wrote:
> >> On 09-11-2011 11:33, Jonathan M Davis wrote:
> >>> On Tuesday, November 08, 2011 21:51:46 Davidson Corry wrote:
> >>>> OK. Not addressing Alex's objections at all, it's not clear to me why
> >>>> anyone would *need* to test the invariant of an object.
> >>> 
> >>> I wouldn't expect it to be something that you'd need to do very often.
> >>> However, if you give access to the member variables in your class or
> >>> struct - either directly or indirectly - allowing code outside the type
> >>> to modify that type's state, then the invariant can be violated. Now,
> >>> it's arguably bad design to allow such access when using an invariant
> >>> (if not in general), but it _is_ a case where the invariant can be
> >>> invalidated.
> >> 
> >> I do think Good Practice (TM) dictates that you shouldn't expose
> >> something as mutable if mutating it violates the object's invariant.
> >> Instead, you should use a property with preconditions.
> >> 
> >> In light of this, I can actually see why assert(obj) testing the
> >> invariant can seem very, very odd. (And I mean, nobody's going to write
> >> assert(this) or something like that...)
> > 
> > You _might_ write assert(this) if you've just called some private
> > functions and wanted to be sure that the invariant is still valid. Since
> > the entire module has access to private functions and variables, and
> > since private functions do _not_ trigger the invariant, it's quite
> > possible for even a well- written class or struct to get a messed up the
> > variant if the module as a whole has bugs. And even if private were
> > restricted to the type, if you were being thorough, you might want to
> > run the invariant within your type after running some private functions.
> > 
> > Still, I wouldn't expect assert(obj) or assert(this) to be common. The
> > only time that I've used it was in debugging when I was trying to figure
> > out when the invariant was invalidated within the type when there was a
> > bug. So, I definitely think that it's useful to be able to explicitly
> > call the invariant, but I'd also expect it to be quite rare.
> 
> Thanks, Jonathan. I had forgotten that something outside of the object
> itself could have mucked about with its innards, disrupting its
> invariant. That is, after all, the reason why the invariant is tested at
> entry to any public method: if it were *not* possible for the invariant
> to have been compromised while the object was "in the wild", there would
> be no need for the test-at-entry.
> 
> I think my point still stands, however. Any time you actually use "obj"
> (by calling one of its public methods) its invariant will be tested, and
> at that point you will learn that "obj" has been compromised.
> Conversely, if you have an "obj" that is compromised but you never use
> it, why would you even *care* about its invariant?
> 
> As far as I can tell, "assert(obj)" MEANS "test the invariant without
> using the object". And I don't see the point of that.

It's occasionally useful when debugging code - particularly when called from 
inside of the object rather than externally.

> Alex's original complaint, if I understand it correctly, is that a bare
> mention of "obj" anywhere else is evaluated as a Boolean "obj !is null".
> ONLY IN "assert(obj)" does it have the special meaning of "obj !is null
> && obj.invariant_holds".

No, his complaint is that it does obj.invariant_holds _without_ checking for 
null. What everyone initially expects is that assert(obj) is identical to 
assert(obj is null) - since that's how it works in all other cases (if, while, 
etc.). The fact that it runs the invariant isn't really a problem IMHO. Since, 
the invariant shouldn't be failing, it's just additional overhead, and since 
it's compiled out in release mode, that really isn't a problem. It's the fact 
that it doesn't first check for null which makes it so that it not only 
completely changes the semantics of implicitly converting a class reference to 
bool but that it will kill your program in cases where the object is null. So, 
as long as it's changed from just testing the invariant to testing for null 
and _then_ testing the invariant if it's not null, I think that it's fine.

As rare as it may be to need to explicitly test the invariant, having a way to 
do so is definitely not detrimental to the language. It's just how it's 
currently implemented that's horribly broken.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list