June 15, 2007
Walter Bright wrote:
> Kristian Kilpi wrote:
> 
>> The problem is that
>>
>>   assert(obj);
>>
>> does not first check if 'obj' is null.
> 
> 
> Yes it does, it's just that the hardware does the check, and gives you a  seg fault exception if it is null.

Asserts were INVENTED to *avoid segfaults*.
June 15, 2007
Why would you want to check an object's invariant? Isn't the compiler doing that before and after you execute a public method? What's the use for it?

Kristian Kilpi escribió:
> 
> This issue has been proposed before. Well, I think it's the time suggest it again...
> 
> The problem is that
> 
>   assert(obj);
> 
> does not first check if 'obj' is null. It just executes the object's invariants.
June 15, 2007
Georg Wrede wrote:
> Walter Bright wrote:
>> Kristian Kilpi wrote:
>>
>>> The problem is that
>>>
>>>   assert(obj);
>>>
>>> does not first check if 'obj' is null.
>>
>>
>> Yes it does, it's just that the hardware does the check, and gives you a  seg fault exception if it is null.
> 
> Asserts were INVENTED to *avoid segfaults*.

What I find odd is that Walter often argues that things in D that *look* like C++ should *act* like C++ as much as possible.  As a C++ user I continually find it bizarre and hard to remember that assert() has these special cases.  There's also something unusual about assert(0), too.  It stays enabled in release mode.  And it's not a seg fault.  But assert on a 0 that happens to have a certain type is.  Odd.  Not making my life any easier I don't think.  I'm sure if I keep poking my brain and telling it "assert(object) is different!", I'll get it internalized eventually, but I really just don't find the "feature" of running invariants all that compelling.

--bb
June 15, 2007
Actually, I would expect it to be a no-op, since the fewer conditions that must be satisfied, the less likely the assert is to fail. Think of a nullary logic ops in scheme, etc. (and, or)...

Georg Wrede Wrote:
> What would your reaction be if you find the following line inside a method?
> 
>    assert();
> 
> What's the first thought? Apart from that it must cause a compiler error since there's no expression at all. What would you expect it to do? If I told you we've fixed gdc so that an empty assert within a method causes immediate assertion of the current instance's consistency, would you approve?

June 16, 2007
(( Top-posting makes it harder to follow for the rest of us...))

Tristam MacDonald wrote:
> Georg Wrede Wrote:
(because of top-posting, watch out for who wrote what)


> Actually, I would expect it to be a no-op, since the fewer conditions
> that must be satisfied, the less likely the assert is to fail. Think
> of a nullary logic ops in scheme, etc. (and, or)...

See way below.

---
        if(){writefln("foo");}

hardly produces a no-op. It gives "expression expected, not ')'". And it should.

(Academically:) if the above error was not errored, then the next thing would be to return false, because the Thruth of Nothing is False.

>> What would your reaction be if you find the following line inside a
>> method?
>> 
>> assert();
>> 
>> What's the first thought? Apart from that it must cause a compiler
>> error since there's no expression at all. What would you expect it
>> to do? If I told you we've fixed gdc so that an empty assert within
>> a method causes immediate assertion of the current instance's
>> consistency, would you approve?

So, logically, assert() should fail.

Nothing (as in (), ) equals false. Thus, it should fail. An assertion fails (even by the grammar in Natural languages, as in English) when it does not produce something true. (Assert Victim has pulse. He has, ok. He has no pulse: dead, assertion failed.)

assert(null)       should produce false.
assert(0)          should produce false.
assert(i)          should produce true if i is non-null, else false.
assert(o)          should produce true if o exists, false otherwise.

Few expect, and even fewer hope that testing for existence (as in assert(o)) actually decides to run some canonicalized method of o "to check if the instance is happy".
June 16, 2007
Bill Baxter wrote:
> Georg Wrede wrote:
>> Walter Bright wrote:
>>> Kristian Kilpi wrote:
>>>> The problem is that
>>>> 
>>>> assert(obj);
>>>> 
>>>> does not first check if 'obj' is null.
>>> 
>>> Yes it does, it's just that the hardware does the check, and
>>> gives you a  seg fault exception if it is null.
>> 
>> Asserts were INVENTED to *avoid segfaults*.
> 
> What I find odd is that Walter often argues that things in D that
> *look* like C++ should *act* like C++ as much as possible.

He should. This is a C family language, designed to woo the C(++) crowd
out of their misery. So, things that "look" the same, should act
unsurprisingly. And things that don't act like those folks expect,
should look something diferent.

> As a C++ user I continually find it bizarre and hard to remember that
> assert() has these special cases.

Exactly my point.

> There's also something unusual about assert(0), too.  It stays
> enabled in release mode.  And it's not a seg fault.  But assert on a
> 0 that happens to have a certain type is.  Odd.  Not making my life any easier I don't think.  I'm sure if I keep poking my brain and telling it "assert(object) is different!", I'll get it internalized eventually, but I really just don't find the "feature" of running invariants all that compelling.

Precisely why I got my blood pressure up with this.

Actually, this particular case doesn't bother me that much since I personally don't use asserts that much. Instead I use writefl(whatever) for my debugging, and either delete those lines when that particular bug is fixed, or leave them as comments. But I can imagine a whole lot of circumstances where it would be wise to leave the assertion in place. The most obvious example would probably be creating a library of red-black trees.

So, this is an issue that carries much _principal_ weight. If we don't close the door for mice right now, then we might as well leave the entire wall open. The end result five years from now won't be that different. (I've lived on the country side, I know.)

Currently, msg 54517, shows that the entire "assert show" is broken.

It might be argued that the whole concept of calling assert and having it sort out for itself whether there's a classInvariant method, is questionable. (In other threads folks have been dying for a compelling example for the need to have compile time introspection (as in, call this method if it exists or do something else reasonable instead). Well, here it is.)

Even if it weren't broken, the question is, should it at all be possible to simply call assert and have it _implicitly_ run methods in the object instance? Such would heavily change the semantics of assert, as compared with any other languages (read: people's expectations).
June 16, 2007
((Reversing another top-post))

Ary Manzana wrote:
> Kristian Kilpi escribió:
> 
>> This issue has been proposed before. Well, I think it's the time suggest it again...
>> 
>> The problem is that
>> 
>> assert(obj);
>> 
>> does not first check if 'obj' is null. It just executes the
>> object's invariants.

> Why would you want to check an object's invariant? Isn't the compiler
> doing that before and after you execute a public method? What's the
> use for it?

First: checking invariants is (most normally) a runtime excercise. Normally the situations that lead to a risk of "breaking" the invariants are due to circumstances the programmer didn't think of at first hand, which naturally suggest a runtime check, usually with Real Use Case Data.


(
Ahh, not for Ary, but for general explaining: object (or more to the point, instance) invariants are not variables that stay the same. Not even variables that stay the same before and after method calls. Rather, they are _logical_ properties of the instance that the instance should want to maintain, even if not explicitly mentioned in the algorithms or source code.

An example:

  We have a class that tracks hours and minutes charged from
  customers.
  Hours worked are added, but for convenience, you can add
  the whole day and then subtract coffee breaks and lunches.
  The invariant for the class HoursWorked would then be

  !(minutes < 0 && minutes => 60)

The invariant is kind of a consistency check between the values of the instance variables. So, an invariant is any function (of one or more of the variables of the instance) that has to resolve to True _whenever_ evaluated between method calls. E.g., a class of carpet sizes would have width and length and area, and the invariant would be width*length==area, and possibly also (width>=0 && length>=0).
)


Second: invariant checking should be run both before and after any method is run, which makes it a property of non-release code.

For that purpose, the invariant section exists in D. (Or will be.)

---

Now, having assert(o) check for the invariants makes for sloppy coding. If the coder is lazy enough to not want to write

  assert(myFancyObject.checkInvariants())

and wants to instead only write

  assert(myFancyObject)

then it should be expected he'd be stupid enough to make un-called-for shortcuts elsewhere too.


At the same time the rest of us have (as it seems) learned to never write

  if (o) {act;}

and instead write

  if (o !is null) {act;}

which not only does contain a double negation, it also is unnecessarily verbose and prone to logical errors. Not to mention, it violates C family heritage -- thanks to a trivial detail, not even related to the issue at hand!
June 16, 2007
What I meant was: if the compiler runs the invariants before and after each method call... when would you like to explicitly check the invariant using assert?

---
SomeObject o = new SomeObject;

// Here the invariant is called automaticaly
o.someMethod();
// Here the invariant is called automaticaly

assert(o); // what's the point? It was done just a second.
---

Unless... Unless you modify a field, and then call the invariant to check if everything is in place. But that's a smell of bad design.

Georg Wrede escribió:
> ((Reversing another top-post))
> 
> Ary Manzana wrote:
>> Kristian Kilpi escribió:
>>
>>> This issue has been proposed before. Well, I think it's the time suggest it again...
>>>
>>> The problem is that
>>>
>>> assert(obj);
>>>
>>> does not first check if 'obj' is null. It just executes the
>>> object's invariants.
> 
>> Why would you want to check an object's invariant? Isn't the compiler
>> doing that before and after you execute a public method? What's the
>> use for it?
> 
> First: checking invariants is (most normally) a runtime excercise. Normally the situations that lead to a risk of "breaking" the invariants are due to circumstances the programmer didn't think of at first hand, which naturally suggest a runtime check, usually with Real Use Case Data.
June 16, 2007
Georg Wrede wrote:
> Walter Bright wrote:
>> Kristian Kilpi wrote:
>>
>>> The problem is that
>>>
>>>   assert(obj);
>>>
>>> does not first check if 'obj' is null.
>>
>>
>> Yes it does, it's just that the hardware does the check, and gives you a  seg fault exception if it is null.
> 
> Asserts were INVENTED to *avoid segfaults*.

I don't know when assert first appeared. But I first encountered them in the 80's, when the most popular machine for programming was the x86. The x86 had no hardware protection. When you wrote through a NULL pointer, you scrambled the operating systems, and all kinds of terrible, unpredictable things ensued. Asserts were used a lot to try and head off these problems.

Enter the 286. What a godsend it was to develop in protected mode, when if you accessed a NULL pointer you got a seg fault instead of a scrambled system. Nirvana! What was even better, was the debugger would pop you right to where the problem was. It's not only asserts done in hardware, it's asserts with:

1) zero code size cost
2) zero runtime cost
3) they're there for every pointer dereference
4) they work with the debugger to let you know exactly where the problem is

Seg faults are not an evil thing, they're there to help you. In fact, I'll often *deliberately* code them in so the debugger will pop up when it hits them.
June 16, 2007
Ary Manzana wrote:
> What I meant was: if the compiler runs the invariants before and after each method call... when would you like to explicitly check the invariant using assert?

In the middle of a method called on it?

> ---
> SomeObject o = new SomeObject;
> 
> // Here the invariant is called automaticaly
> o.someMethod();
> // Here the invariant is called automaticaly
> 
> assert(o); // what's the point? It was done just a second.
> ---
> 
> Unless... Unless you modify a field, and then call the invariant to check if everything is in place. But that's a smell of bad design.

If the field was modified externally, I agree.
But if the field was modified inside a method of the object, that method might want to check consistency before continuing with other stuff (that presumably doesn't start with calling a public method, or it would still be redundant).