On 03/17/2011 06:12 PM, Walter Bright wrote:
On 3/17/2011 3:08 PM, Andrei Alexandrescu wrote:
if (!condition) { writeln("my message %s %s", __FILE__, __LINE__);
assert(0); }

I am strongly opposed to using enforce() for bug detection.

There's nothing wrong with encapsulating this idiom (if frequent).
That's what
essentially alwaysAssert does. So you're right but without contradicting
dsimcha's suggestion.

Sure, but there is plenty wrong with using enforce() for bug detection
even if alwaysAssert does not exist. For one thing, such uses encourage
others to misunderstand and misuse enforce.

(I'm not sure what you even want to convey here as your statement does not contradict or oppose any other, yet is grammatically formulated as if it did. One may as well reply with "Yes, but the water's wet.")

No question enforce would be wrong for bug detection. Using this would be just as wrong:

if (undefinedState) throw new Exception("Hmm, odd...");

By packaging the if/throw combo, enforce becomes a notion, a part of the vocabulary, a meme if you wish. That makes it neither more nor less wrong for bug detection, but makes it plenty better for systematic error handling.

Now, there is an additional issue that may confuse people on the relative roles of assert and enforce. We have faced the question, how do we validate arguments to a function in Phobos?

Initially I used enforce() all over the place, under the assumption that Phobos' user and Phobos are separate entities. Therefore, any argument coming from outside Phobos would be necessarily considered I/O from within Phobos and therefore scrubbed accordingly.

Then there was pressure on loss of efficiency due to checking, so I and others replaced certain instances of enforce() with assert(). This is not wrong at all. Instead, it reflects a different view of the dynamics between Phobos and its user: now Phobos + user code is considered as an entity that works together. So a failing assert in Phobos could describe a bug in Phobos itself or one in the application code that uses it. This is more ambiguous but not one bit less correct under the stated assumptions.

Additionally, alwaysAssert is an obvious one liner. I think such things
need to be very frequently used to consider them part of the standard
library. Otherwise, we risk Phobos becoming a morass of trivia.

enforce() is an obvious one liner too. Size is not the only means to assess the usefulness of an abstraction. Two others are frequency of the pattern (think "writeln") and ascribing a meaningful name to it (think "unittest").

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-12.html#%_sec_1.3 is a good read, let me paste:

=========================
We have seen that procedures are, in effect, abstractions that describe compound operations on numbers independent of the particular numbers. For example, when we

(define (cube x) (* x x x))

we are not talking about the cube of a particular number, but rather about a method for obtaining the cube of any number. Of course we could get along without ever defining this procedure, by always writing expressions such as

(* 3 3 3)
(* x x x)
(* y y y)

and never mentioning cube explicitly. This would place us at a serious disadvantage, forcing us to work always at the level of the particular operations that happen to be primitives in the language (multiplication, in this case) rather than in terms of higher-level operations. Our programs would be able to compute cubes, but our language would lack the ability to express the concept of cubing. One of the things we should demand from a powerful programming language is the ability to build abstractions by assigning names to common patterns and then to work in terms of the abstractions directly. Procedures provide this ability. This is why all but the most primitive programming languages include mechanisms for defining procedures.
=========================


Andrei

Reply via email to