July 14, 2004
On Tue, 13 Jul 2004 22:10:02 -0400, Ben Hinkle <bhinkle4@juno.com> wrote:
> Matthew wrote:
>
>>
>> "Regan Heath" <regan@netwin.co.nz> wrote in message
>> news:opsa3p7mzu5a2sq9@digitalmars.com...
>>> On Wed, 14 Jul 2004 10:07:39 +1000, Matthew
>>> <admin@stlsoft.dot.dot.dot.dot.org> wrote:
>>> > "Regan Heath" <regan@netwin.co.nz> wrote in message
>>> > news:opsa3k2sce5a2sq9@digitalmars.com...
>>> >> On Tue, 13 Jul 2004 18:39:05 +1000, Matthew Wilson
>>> >> <dmd@synesis.com.au> wrote:
>>> >> > Can I register yet another request for this long-looked-for 
>>> feature?
>>> >> >
>>> >> > I'm finding it rather painful that the output just prints "Error:
>>> >> > AssertError Failure vector(390)". It's just a PITA.
>>> >> >
>>> >> > Can we get this for 1.0?
>>> >>
>>> >> I can't see the point myself.
>>> >>
>>> >> asserts only occur in debug builds, so end users never see them, so
>>> >> it's only you the developer that sees them, in which case you simply
>>> >> open the source and you can see what asserted.
>>> >
>>> > Nonsense. What about users of libraries, i.e. developers?
>>>
>>> Open source or closed? If it's open source you can open the source and
>>> look.
>>
>> Yes, but sometimes the assert condition can be complex. If there's a
>> simple message telling the user immediately what the problem is, then
>> they've saved time. I can't see why that's not an attractive thing? It
>> helps in many circumstances, but costs nothing and does no harm.
>
> Here are a few message_assert's I've found in src/phobos/etc/c/stlsoft:
>
>  winstl_message_assert("Attempting to increment an invalid iterator!", NULL
> != m_handle);
>
>  winstl_message_assert("Dereferencing end()-valued iterator", 0);
>
>  unixstl_message_assert("Shared search handle being destroyed with
> outstanding references!", 0 == cRefs);
>
> and it looks generally like these asserts are for cases when the user has
> incorrectly used the library. I agree for these types of asserts (if they
> should be asserts) a message helps the user correct their code. But a
> typical assert Walter uses is something like
>
>  Internal Error: ..\ztc\cgcod.c 614
>
> which means Walter (not the user) messed up and all he needs are some
> reproduction steps and the file and line number. Personally I tend to use
> asserts like you do and consider invalid usage to be assertable where
> Walter keeps asserts to only internal usage (I think Arcane Jill had also
> posted that's how she uses asserts). So I think it makes sense to have two
> different assert mechanisms for these two different usage models.
> Maybe there should be some sort of "private assert" and "public assert" and
> the public one has message strings and the private one doesn't.

Maybe... I think the crux of it is "what is assert worthy and what is an exception?"

A commonly used assert, is one used when a parameter to your API is incorrect. Typically when using Windows C API calls there is an error code returned which says invalid parameter. As we don't use those in D, do we throw an exception OR use an assert in this case?

I think in this case an exception allows the user of your API more flexibility. It may not be a fatal error for this particular API call to fail, they may want to catch and handle the exception.

Using the above examples, an exception may be valid here...

>  winstl_message_assert("Attempting to increment an invalid iterator!", NULL
> != m_handle);

not sure, not really enough context.

In other examples an assert may be perfectly valid, like here...

>  unixstl_message_assert("Shared search handle being destroyed with
> outstanding references!", 0 == cRefs);

this seems to me to be one too many calls to a free function, probably due to a buggy algorithm/loop they used to call it.

Basically what I'm saying is perhaps sometimes we use asserts and should have used an exception and vice-versa.

I did voice an idea for an overload function onAssert() so as to modify the behaviour of how it outputs the assert. I don't think that is required any mode, I think if it's an error the end user needs to see it should be an exception.

Regan.

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
July 14, 2004
In article <cd1tgu$26qd$2@digitaldaemon.com>, Matthew says...

>> asserts only occur in debug builds, so end users never see them, so it's only you the developer that sees them, in which case you simply open the source and you can see what asserted.
>
>Nonsense. What about users of libraries, i.e. developers?

Not sure I agree with this. My Deimos library stuff does have asserts, but only because I expect them never to happen. They don't indicate that the library USER has done anything wrong, merely that I have a bug to fix.

Fortunately, I am here, and people who discover such bugs can tell me about it. If I were not contactable, it still wouldn't matter too much because Deimos is open source, and so, theoretically, someone ELSE could fix it.

But in the circumstance where (a) the library author were not contactable, and
(b) the project were not open source, an assert would be a very bad thing to
encounter. A throw of an exception (with a suitable error message) would be much
more appropriate, methinks.

Arcane Jill



July 14, 2004
In article <opsa32o5pf5a2sq9@digitalmars.com>, Regan Heath says...
>
>A commonly used assert, is one used when a parameter to your API is incorrect. Typically when using Windows C API calls there is an error code returned which says invalid parameter. As we don't use those in D, do we throw an exception OR use an assert in this case?

We throw an exception, obviously. Otherwise you will never be able to test what happens when the user provides invalid input.

Why not? Because in a debug build, the asserts will prevent invalid input from reaching the function, so the horror of that ACTUALLY HAPPENING (with consomate access violations, buffer overflows, whatever) will simply not occur ... in a debug build. So you'll never test it, and never write code to deal with bad user input.

But invalid user input will make it through those asserts in a release build. And then guess what's gonna happen after that? Ouch!

D is not C. A D assert is not the same thing as C assert.

Arcane Jill



July 14, 2004
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:cd2o1k$mru$1@digitaldaemon.com...
> In article <cd1tgu$26qd$2@digitaldaemon.com>, Matthew says...
>
> >> asserts only occur in debug builds, so end users never see them, so it's only you the developer that sees them, in which case you simply open the source and you can see what asserted.
> >
> >Nonsense. What about users of libraries, i.e. developers?
>
> Not sure I agree with this. My Deimos library stuff does have asserts, but only because I expect them never to happen. They don't indicate that the library
USER
> has done anything wrong, merely that I have a bug to fix.
>
> Fortunately, I am here, and people who discover such bugs can tell me about it. If I were not contactable, it still wouldn't matter too much because Deimos is open source, and so, theoretically, someone ELSE could fix it.
>
> But in the circumstance where (a) the library author were not contactable, and
> (b) the project were not open source, an assert would be a very bad thing to
> encounter. A throw of an exception (with a suitable error message) would be
much
> more appropriate, methinks.

I don't agree. Exceptions are for exceptional conditions, i.e failures, not human errors. If you want to be "strict", then the right thing to do when a DbC condition is violated is to halt. An exception is not the appropriate response.



July 14, 2004
"Matthew" <admin@stlsoft.dot.dot.dot.dot.org> wrote in message news:cd2rij$tra$1@digitaldaemon.com...
>
> "Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:cd2o1k$mru$1@digitaldaemon.com...
> > In article <cd1tgu$26qd$2@digitaldaemon.com>, Matthew says...
> >
> > >> asserts only occur in debug builds, so end users never see them, so it's only you the developer that sees them, in which case you simply open the source and you can see what asserted.
> > >
> > >Nonsense. What about users of libraries, i.e. developers?
> >
> > Not sure I agree with this. My Deimos library stuff does have asserts, but
only
> > because I expect them never to happen. They don't indicate that the library
> USER
> > has done anything wrong, merely that I have a bug to fix.
> >
> > Fortunately, I am here, and people who discover such bugs can tell me about
it.
> > If I were not contactable, it still wouldn't matter too much because Deimos
is
> > open source, and so, theoretically, someone ELSE could fix it.
> >
> > But in the circumstance where (a) the library author were not contactable,
and
> > (b) the project were not open source, an assert would be a very bad thing to
> > encounter. A throw of an exception (with a suitable error message) would be
> much
> > more appropriate, methinks.
>
> I don't agree. Exceptions are for exceptional conditions, i.e failures, not
human
> errors. If you want to be "strict", then the right thing to do when a DbC condition is violated is to halt. An exception is not the appropriate response.

As the man himself says, if you don't want your process to halt when it's actually in an unsound state, what do you want it to do?

One more thing: it seems to me that everyone always assumes that assertions are a debug-time feature only. There's absolutely no reason why this should be so, and I've worked on systems where they were always active (albeit they had different actions in debug and release mode).




July 14, 2004
In article <cd2rij$tra$1@digitaldaemon.com>, Matthew says...

>I don't agree. Exceptions are for exceptional conditions, i.e failures, not human errors. If you want to be "strict", then the right thing to do when a DbC condition is violated is to halt. An exception is not the appropriate response.

Eh?



July 14, 2004
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:cd33r9$1cjn$1@digitaldaemon.com...
> In article <cd2rij$tra$1@digitaldaemon.com>, Matthew says...
>
> >I don't agree. Exceptions are for exceptional conditions, i.e failures, not
human
> >errors. If you want to be "strict", then the right thing to do when a DbC condition is violated is to halt. An exception is not the appropriate
response.
>
> Eh?

Errors: A human failure to have coded something correctly.
Fault: A condition that may legitimately result in the lifetime of a process
within the context of its execution environment.

Passing a null-pointer is an error.
Failure to write to a file through lack of disk space is an exception.

In almost all cases, a process should handle an exception, and take remedial action. Of course, one such action is to terminate the process - e.g. when out of memory - but that's rarely the best answer.

The point made by Bertrand Meyer is that errors, which reflect coding failures, *not* environmental conditions, should result in termination of the process. Although this seems somewhat extreme, he sagely posits the question "what would you have an erroneous process do?".

Is that any clearer?


July 14, 2004
In article <cd33r9$1cjn$1@digitaldaemon.com>, Arcane Jill says...
>
>In article <cd2rij$tra$1@digitaldaemon.com>, Matthew says...
>
>>I don't agree. Exceptions are for exceptional conditions, i.e failures, not human errors. If you want to be "strict", then the right thing to do when a DbC condition is violated is to halt. An exception is not the appropriate response.
>
>Eh?



So what's wrong with this then?

#    Int sqrt(Int x)
#    {
#        if (x < 0) throw new IntException("sqrt(x) not defined for x < 0");
#        //...
#    }

An assert is DEFINITELY not the right thing here. The input could come from the intermediate result in a long calculation. Whether or not x is negative may not be deducable at compile time. So it's an error, and that's EXACTLY what exceptions are for.

And it will only halt the program if the exception is not caught. (Which is fair enough, I think). Anyone canny enough to wrap such calls in a try block can do their own tidy-up. And if they don't they'll get a nice error message.

On the other hand, the Int class also supplies some LOW LEVEL functions. Here's one:

#    uint bigintLLAdd(uint* d, uint* x, uint xLen, uint* y, uint yLen)
#    in
#    {
#        assert(xLen >= yLen);
#    }

whereby the input MUST obey (xLen >= yLen), and if it doesn't then it's a bug on the part of the caller. The assert tells whoever wrote the calling function to fix /their/ bug. This sort of thing I only ever do on seriously low level code, at the pointer and buffer level, where undefined behavior is the guaranteed result of naff input. As Norbert (I think) said, an "in" condition is part of the function's interface.

So what do YOU think is the correct thing to do then, in both of these circumstances? And when exactly would you throw an exception?

Note that the phrase "exceptional conditions, i.e failures" is nonsense, since "exceptional conditions" does NOT mean the same thing as "failures". (The Latin abbreviation i.e. stands for "id est", which means "that is", "that is to say", or "in other words"). They're called "Exceptions" because they happen in exceptional (that is, rare, uncommon) circumstances. They're not called "Failures", a word which means something completely different. Perhaps you could clarify your meaning?

Arcane Jill


July 14, 2004
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:cd35jt$1fll$1@digitaldaemon.com...
> In article <cd33r9$1cjn$1@digitaldaemon.com>, Arcane Jill says...
> >
> >In article <cd2rij$tra$1@digitaldaemon.com>, Matthew says...
> >
> >>I don't agree. Exceptions are for exceptional conditions, i.e failures, not
human
> >>errors. If you want to be "strict", then the right thing to do when a DbC condition is violated is to halt. An exception is not the appropriate
response.
> >
> >Eh?
>
>
>
> So what's wrong with this then?
>
> #    Int sqrt(Int x)
> #    {
> #        if (x < 0) throw new IntException("sqrt(x) not defined for x < 0");
> #        //...
> #    }
>
> An assert is DEFINITELY not the right thing here. The input could come from the intermediate result in a long calculation. Whether or not x is negative may not be deducable at compile time. So it's an error, and that's EXACTLY what exceptions are for.

You're making assertions here (pardon the pun) that totally miss the point. An assertion is a contract enforcement. Failure to meet the contract should result in failure.

In the code above you would, one might hope, document that your sqrt function is happy to receive -ve values, in which case sqrt will throw an IntException. Given that, throwing the exception is valid.

If I was writing it, I would have it as part of sqrt's precondition that x>=0. Thus, if x < 0, I would issue an assertion (in the broad sense of the term, not necessarily do assert()), and the process would halt.

So, your assertion that "An assert is DEFINITELY not the right thing here" is only correct if you stipulate that -ve values are valid wrt to the contract for sqrt. If that's not the case, then it's just hot air, and your shouting is crass.

> And it will only halt the program if the exception is not caught. (Which is
fair
> enough, I think). Anyone canny enough to wrap such calls in a try block can do their own tidy-up. And if they don't they'll get a nice error message.

And imagine all the nice extra code doing all this defensive programming. Yummy!

I can only recommend you read Meyers book. A strong indication of the quality of the work is the degree to which it has influenced Walter's thinking (something notoriously difficult to do) despite the fact that he slags Walter off in Chapter 14.

> On the other hand, the Int class also supplies some LOW LEVEL functions. Here's one:
>
> #    uint bigintLLAdd(uint* d, uint* x, uint xLen, uint* y, uint yLen)
> #    in
> #    {
> #        assert(xLen >= yLen);
> #    }
>
> whereby the input MUST obey (xLen >= yLen), and if it doesn't then it's a bug
on
> the part of the caller. The assert tells whoever wrote the calling function to fix /their/ bug. This sort of thing I only ever do on seriously low level code, at the pointer and buffer level, where undefined behavior is the guaranteed result of naff input. As Norbert (I think) said, an "in" condition is part of the function's interface.
>
> So what do YOU think is the correct thing to do then, in both of these circumstances? And when exactly would you throw an exception?

I can't be bothered to plough through all the shouting in the second one, but I can tell you I'd make the function conform to its contract.

> Note that the phrase "exceptional conditions, i.e failures" is nonsense, since "exceptional conditions" does NOT mean the same thing as "failures". (The Latin abbreviation i.e. stands for "id est", which means "that is", "that is to say", or "in other words"). They're called "Exceptions" because they happen in exceptional (that is, rare, uncommon) circumstances. They're not called "Failures", a word which means something completely different. Perhaps you
could
> clarify your meaning?



July 14, 2004
teqDruid wrote:

>void myAssert(bit condition, char[] message)
>{
>	if (condition)
>		throw new myException(message);
>}
>
>I'm not sure what it is you're looking for that can't be done with
>Exceptions.
>
>  
>

The thing is the line-number+filename.  Now you can do a stack trace but that's not very convenient in many situations, particularly if your working on a different OS which has no general console.

Also message assert need to be standardised.  Its an extreamly useful tool.  Each developer (and they will) should not need to write their own.

-- 
-Anderson: http://badmama.com.au/~anderson/