Wed Dec 17 10:26:42 CET 2003
Richard A. O'Keefe wrote:
> The C equivalent of (SHOULDNT) is abort(). Not, by the way, assert(0).
If that's the case, SHOULDNT shouldn't be in the language.
After all, forcing the execution of the program to a halt is unmodular:
the caller might want to run the code and try an alternate strategy.
(Heck, that's what Erlang is all about: surviving faulty code that does
thing's that shouldn't happen.)
> Is it clear to everyone that
> "This code must raise an exception at run time"
> "This code is in error"
> are different?
This classification isn't complete, and I think the ongoing discussion
is at least partially senseless because wrong distinctions of this kind
are constantly being made.
Actually, Erlang has more failure modes (and this list may not even be
1. Erroneous code that's rejected by the compiler. This includes stuff
like "1 = 2 3".
2. Code that will raise an exception. Example: "1 = 2".
3. Code that will terminate the process. Essentially, that's code that
doesn't catch all exceptions that may occur.
4. Code that will terminate the Erlang node.
5. Code that will terminate all communicating Erlang nodes.
Category 2 is what most confusion comes from: depending personal
definitions, one may consider it erroneous or not (and either definition
makes sense, depending on the point of view).
There's another source of confusion: Some people here argue that a
compiler shouldn't change the semantics of the language, but is that
indeed the case? Both syntax and semantics of Erlang have changed over
the years, in in an upwards-compatible fashion.
> Is it also clear that
> "This code is obviously silly"
> "This code must raise an exception at run time"
> are different? Lint warns about things that are clearly silly,
> yet perfectly legal, and perfectly harmless. For example,
> x == y;
> as a C statement is perfectly well defined, and quite harmless,
> yet lint warns about it because you probably didn't mean it.
> A C compiler which refused to compile such a program would not
> be helpful, it would be buggy.
A C compiler would emit a warning and be compliant.
If I were to decide, I'd adopt a similar policy: issue warnings about
constructs like 1=2.
However, I dislike somethine entirely different about them. There's
clearly a need to make a computation fail, and different people use
different idioms to express is. Some say 1=2, others say a+0, and I saw
mentions a handful others.
While that's neat, it's also an unnecessary maintenance obstacle.
Whenever a maintainer sees such code, he has to (a) find out what this
code does (which will take more time than usual because he'll have to
revisit the usual assumption that code isn't written for raising
exception), (b) figure out whether the code is raising the exception
intentionally or not.
There are two additional disadvantages: (c) it's impossible to do a grep
to see whether any temporary exception-raisers were accidentally left in
some code that's considered ready for production release, and (d) if the
code does raise an exception, it will give the maintainer wrong
information: the true error is that the system is trying to execute
unwritten code, but the system will give a different error message.
I'm quite mystified why there isn't a "niy" (not implemented yet) or
"tbd" (to be determined) routine, that explicitly raises an exception
saying "fatal error: trying to execute code that has not yet been
written" (or something similar).
Once such a routine is in place, the question whether changing the
semantics of obviously silly constructs is a no-brainer: if there's no
useful purpose for them, their semantics is irrelevant and can be
changed. One may adopt a more conservative approach and maintain
compatibility with legacy code, so a warning would probably be more
appropriate. An even better option would be if that warning could be
turned into an error for those shops who want strict discipline (not all
shops need that, but sometimes there are good reasons to turn on the
equivalent of -Wall --warnings-as-errors).
> It is possible to make (=)-for-(==) and (==)-for-(=) errors in
> Erlang, and lint checking for Erlang might warn about them even
> though they are legal.
> Whether a particular piece of apparent silliness is worth warning
> about is an empirical question: how often do programmers make the
> kind of mistake that results in an instance of that pattern, and
> how often do they intend it?
And, more importantly: how easy is it to make the compiler detect that
pattern, and how likely is it that the compiler will make errors when
identifying such patterns?
> I've worked on a couple of compilers for languages that supported
> exception handling. (I _think_ mine was the first paper on doing this
> for Prolog, except that Quintus insisted on yanking it from the conference
> after it was accepted.) Exception handling can be very tricky to get
> right. (There's a debate raging in the Clean mailing list at this moment.)
> ANSI Smalltalk exception handling is a case in point; to me it seems
> insanely complicated, and it's not clear that Squeak has got it 100% right
> yet. This means that especially when you are maintaining compilers, you
> _need_ simple test cases which are certain to cause exceptions because
> that's what you're testing.
There's always the explicit exception raising statement. Any language
that has exceptions should have such a statement, and Erlang does it right.
Actually, I don't think that generating a test case should be a problem,
ever. There's always the possibility to do unit testing. You'll have to
structure the compiler so that it has units to be tested, but this
restructuring will clean up the compiler considerably, making is more
stable and reliable, so this is a good idea anyway. Loss of test cases
due to changes in language syntax or semantics is just an indicator that
the compiler is badly structured IMNSHO.
More information about the erlang-questions