PEP new assert idiom

  • Thread starter =?ISO-8859-1?Q?F=E1bio?= Mendes
  • Start date
N

Neil Benn

Hello,

While I get what you are talking about - I think you are
missing the point of an assert function. If you document an assert
(which you should do) you are saying :- if you give me something which
follows these rules, then I will do this - thankyouverymuch.

In both Java and Eiffel, you have the option to compile the code
without the assert checking in - giving you a tight debug stuation and
a looser and faster run-time situation (as long as your code is tested
and robust). However Eiffel's require and ensure are Assert
statements on steroids!!

A classic text on this is by Bertrand Meyer - the inventor of
Eiffel. Although Eiffel's philosophy is very different than python's
it's a classic text. Here's a link to a short article about it :

http://archive.eiffel.com/doc/manuals/technology/contract/

Cheers,

Neil
 
J

John Roth

Fábio Mendes said:
I meant expression instead of statement, sorry, that's my fault. It's a
minor cosmetic change I should say, only to avoid long grouping of
expressions with an 'and' operator. It's better expressed as: let the
commas take the place of 'and' in assertion verifications... Maybe that
could be extended to other parts of the language, but the only place I
think it would be useful is in assertion statements.

I see. That might have a syntactic difficulty, though, since the
comma is already in use as the tuple constructor operator.

John Roth
 
J

John Roth

Gerrit said:
I think 'assert' being a statement is on Guido's regrets list. exec and
print are on his regrets list: both should have been a function. I
think the same holds for assert, although I'm not sure.


In my opinion, assert is almost useless. It can sometimes be useful for
debugging purposes, but beyond that, it isn't. The exception raised by
'assert' is always AssertionError. That is a major disadvantage, because
it's not specific. If a method I'm calling would raise an AssertionError
is some cases, and I want to catch it, I'm catching too much. Creating a
new exception-class and raising that one is better because of this.

I see assert as a statement of an invariant: each and every time
I come here this *must* be true. I don't see it as a statement
of wishful thinking: when I come here, this should be true or
I'm going to have problems.

For me, an assert failing is a programing error in the caller,
not in the method with the assert! Trying to catch an
assert is a misuse of what the statement provides.

Besides which, you can always dress up an assert
with a string that can be printed, and then further
stick variables into that string with %.

John Roth
 
P

Paul Rubin

John Roth said:
I see assert as a statement of an invariant: each and every time
I come here this *must* be true.

Yes, that was the intention of the assert statement. However, there's
a very great temptation to use it for a somewhat different purpose,
namely checking data validity. When there's a great temptation to
misuse some feature to do X when it's really intended for Y, that's a
sign that it's time to add an equally convenient feature intended for
doing X.
For me, an assert failing is a programing error in the caller, not
in the method with the assert! Trying to catch an assert is a misuse
of what the statement provides.

There's a slight non-sequitur there. Every large system contains
programming errors, and assert statements are a good way to detect the
errors. If an assert fails and isn't caught, the system crashes.
Crashing a running system on detection of the slightest programming
error is not always an acceptable thing to do. Sometimes you have to
log the error and try to recover from it, disable the feature where
the error happened until someone can figure out what went wrong, or
whatever; but not crash. So you need to be able to catch assert
failures.
 
?

=?ISO-8859-1?Q?F=E1bio?= Mendes

Em Dom, 2004-11-07 às 08:56 +0000, Steven Bethard escreveu:
I'm not sure that I understand you correctly, but if you're saying that the
commas in a function argument list indicate an implicit line continuation, I
think this is probably not correct. It's the unclosed parentheses that indicate
the line continuation, not the commas -- this is why you can write a function
argument list across multiple lines, but it's also why you can write a tuple
across lines:

... y, z):
... print x, y, z
...

Now it makes sense to me... i thought that the commas was responsable for line continuation because this is how we usually separate the functions arguments and list/tuple/dictionary items. I never thought that this would work:
.... 'bar',
.... 'bar':
.... 'foo' }

But it works indeed ;)

I think my PEP is getting more and more nonsensical... I give up! Thanks for your advice guys,
Fabio
 
?

=?ISO-8859-1?Q?F=E1bio?= Mendes

[...]
Nope, comma can never be used as implicit line continuation in Python
(that's different from some other languages). The opened and yet
unclosed parentheses are what cause several physical lines to be part of
the same logical line -- not commas, nor other operator or punctuation.
[...]
You may be associating "commas continue lines" with "function arguments"
because function definitions and calls DO use parentheses, and separate
arguments with commas. But it's really not an ideal mental model.

You're right, that's a subtle misconception that don't give syntax
errors so I never realize to be the case ;-) I was writing multiple line
dictionaries like this:
.... key: value
.... key2: value2 }

The backslash is completely uncecessary (and ugly!). Thanks for
clarification,

-Fabio
 
J

John Roth

Paul Rubin said:
Yes, that was the intention of the assert statement. However, there's
a very great temptation to use it for a somewhat different purpose,
namely checking data validity. When there's a great temptation to
misuse some feature to do X when it's really intended for Y, that's a
sign that it's time to add an equally convenient feature intended for
doing X.


There's a slight non-sequitur there. Every large system contains
programming errors, and assert statements are a good way to detect the
errors. If an assert fails and isn't caught, the system crashes.
Crashing a running system on detection of the slightest programming
error is not always an acceptable thing to do. Sometimes you have to
log the error and try to recover from it, disable the feature where
the error happened until someone can figure out what went wrong, or
whatever; but not crash. So you need to be able to catch assert
failures.

I think I didn't say it quite well enough. Of course you catch
assert errors, but you classify them the same as non-recoverable
environmental errors: you scrub whatever unit of work you were
working on, log the error and try to recover the application so
the user can continue.

I think we're in agreement that what you don't want to do
is try to catch and recover from a specific assert error.

John Roth
 
C

Carl Banks

Gerrit said:
I think 'assert' being a statement is on Guido's regrets list. exec and
print are on his regrets list: both should have been a function. I
think the same holds for assert, although I'm not sure.

I don't recall seeing assert on that list. Unlike print and exec,
what assert does can't be done by a function.

In my opinion, assert is almost useless. It can sometimes be useful for
debugging purposes, but beyond that, it isn't. The exception raised by
'assert' is always AssertionError. That is a major disadvantage, because
it's not specific.

Actually it is, if you use assert correctly. I'll get to that.

If a method I'm calling would raise an AssertionError
is some cases, and I want to catch it, I'm catching too much. Creating a
new exception-class and raising that one is better because of this.

If you use assert correctly, you either wouldn't want to catch
AssertionError, or you'd want to catch it at a rather high level and
print a message about a bug in the program.

I don't see the use of a statement like
"assert isinstance(message, basestring)".
[snip]

Generally speaking, this is an incorrect use of assert. I don't
approve of this use of assert.

The proper use of assert is to declare that a certain condition is
impossible. That is, if the program is bug-free, this condition will
never happen. An assertion error should never be raised unless
there's a bug in the program.

Here's a ridiculous, and incorrect, but illustrative, example of its
proper use:

def f(y):
x = y*y
assert x >= 0

As we know, multiplying a real number by itself always produces a
positive number (for the sake of argument, let's ignore the fact that
y could be a complex number). Thus, is it impossible for x to be
negative. Impossible, that is, unless there's a bug. The assert
statement declares this to be an impossible condition. If this
condition does not hold, it can't be bad input. It's a bug.
Obviously, this is a silly example, but real world examples aren't so
silly.

Because it's an "impossible" condition, it only needs to be checked in
debugging builds. This is where the magic of the assert statement
comes in: in an optimized build, the assertion is not checked. Thus
it's an optimiztion. If you change assert into a function, Python can
no longer optimize the assertion away, because the function argument
is always evaluated.

This however, raises a question: is it a premature optimization? I
would say yes and no. For simple assertion, like assert x >= 0, the
optimization is premature and probably not worth justifying an assert
statement. However, I still like having it, just to document that the
condition being checked is intended to be an impossible condition, as
opposed to bad input or an operating system error.

However, there are some impossible conditions that are simply not
premature optimizations by anyone's definition. Let me show you an
example:

def some_public_function(tree1, tree2):
assert one-to-one(tree1,tree2)
...

In this case, I have two tree heirarchies which the program is to keep
1:1 at all time (i.e., for every node in tree1, there is a
corresponding node in tree2). There are hundreds of functions
operating on both trees, and all of them have to make sure to update
both hierarchies. If there is any exit point of a public function
where these trees are not one-to-one, then it's a bug.

The problem is, checking the whole hierarchy every time you call a
public function is simply too expensive for production code. An
assert statement lets you optimize this call away, and very
conveniently. I feel that power justifies the existence of assert.

Assert statements have found many, many bugs in my larger projects, so
I would be very sad to see them go away. HOWEVER, in the end, I could
easily live without it. Simple assertions don't cost much to check in
production code. Expensive assertions I usually put in a function
anyways, so I can optimize it away by simply not calling it unless a
debug flag is set.

In my opinion, assert should be deprecated and then removed in Py3K:
assertions are redundant, unspecific, and conflict with the philosophy
of duck typing and EAFP.

What do others think of this?

I don't want to see it disappear because it has valid uses.

I think it would be wise to discourage the use of assert for purposes
it wasn't intended for, such as the example you gave.

IMO, the best way to do this is to have assertion OFF by default.

The way Python is set up now is to have a default mode and optimized
mode, the optimized mode not running asserts. I would change that. I
suggest that Python should instead have a default mode and a debugging
mode, and that assertions should only be checked in debugging mode.
Ordinary Python runs, without a -g flag, would simply ignore assert
statements.
 
R

Raymond Hettinger

[Fábio Mendes]
I think my PEP is getting more and more nonsensical... I give up!

LOL. The PEP is the same. It is it's author's world view that has changed ;-)


Raymond
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top