Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > PEP new assert idiom

Reply
Thread Tools

PEP new assert idiom

 
 
=?ISO-8859-1?Q?F=E1bio?= Mendes
Guest
Posts: n/a
 
      11-06-2004
I'm sorry if it's an replicate. Either my e-mail program is messing with
things or the python-list sent my msg to /dev/null. I couldn't find
anything related in previous PEP's, so here it goes a very early draft
for a new "assert" syntax:

This was inspired in Ruby's assert syntax. I'm not familiar with Ruby at
all, so the chances are that this piece of code is broken, but I think
the idea is very obvious. In Ruby, assert is simply a method which gets
a block argument:

>>> assert 'Errormsg' {
>>> statement 1
>>> statement 2
>>> (...)
>>> statement n
>>> }


This elegant syntax is NOT equivalent to python's not so ellegant:

>>> erromsg = 'Errormsg'
>>> assert statement 1, errormsg
>>> assert statement 2, 'errormsg
>>> (...)
>>> assert statement n, errormsg


In Ruby, the Assertion error is raised if executing statement 1, then 2,
then 3... etc raises an error. This is a subtle thingm the error COULD
NOT be raised if each statement is executed alone, as each statement may
have side effects which make the order of execution relevant. To
suceccefully emulate this behaviour, the python programmer have to
resort to a even more cumbersome solution:

>>> foo = lambda : (statement 1) and (statement 2) ... (statement n)
>>> assert foo, 'Errormsg'


My proposal is to add the following syntax to the language:

>>> assert (statement 1), (statement 2), ... (statement n), 'Errormsg'


Or, if the user prefers, the traditional comma rules also applies:

>>> assert \
>>> statement1,
>>> statement2,
>>> (...)
>>> statement n,
>>> 'Errormsg'


This simple syntax change introduces a very useful idiom for unittesting
and may equally be useful in other kinds of code. The most problematic
issue, I see, is the potential ambiguity a assert usage:

>>> assert statement 1, ..., statement n, string


As the 'Errormsg' argument is optional, it could be interpreted either
as being the statement (n + 1) or as the errormsg. This is not a
non-issue as the following syntax is valid in the current implementation
and is very useful:

>>> st = ''
>>> assert st

Traceback
....
AssertionError

This is useful to assert that a string is not empty. My proposal is that
assert will always check all statements, (including the eventual error
message) and issue AssertError exceptions if find any problem. This will
catch only empty strings. If the last argument is a string, and an a
False statement was found, it will print the last argument in the shell.

The only piece of code I see would be broken in the new implementation
is:

>>> assert statement, ''


This will always raise an exception in the new implementation on the
opposition to the current behaviour in which the exception is raised
only if 'statement' is false, returning an empty error message. I don't
see any use for this pattern of code and is very unlikelly anyone has
ever implemented it, so I guess nobody would mind breaking this.

I'm interested to write a formal PEP if I receive good feedback from the
community, but I never wrote a PEP before, and (the worst problem) my
english is not so good. Anyone helps?

Thanks,
Fabio
 
Reply With Quote
 
 
 
 
Alex Martelli
Guest
Posts: n/a
 
      11-06-2004
Fábio Mendes <(E-Mail Removed)> wrote:
...
> This elegant syntax is NOT equivalent to python's not so ellegant:
>
> >>> erromsg = 'Errormsg'
> >>> assert statement 1, errormsg
> >>> assert statement 2, 'errormsg
> >>> (...)
> >>> assert statement n, errormsg


Why isn't this equivalent? Apart from the fact that you keep, here and
elsewhere, using 'statement' where you hopefully mean 'expression' --
you cannot assert a statement, you can only assert an expression.

> In Ruby, the Assertion error is raised if executing statement 1, then 2,
> then 3... etc raises an error. This is a subtle thingm the error COULD
> NOT be raised if each statement is executed alone, as each statement may
> have side effects which make the order of execution relevant. To


Can you give one Python example where the sequence of asserts would
behave differently from what you propose? I cannot see any.

> suceccefully emulate this behaviour, the python programmer have to
> resort to a even more cumbersome solution:
>
> >>> foo = lambda : (statement 1) and (statement 2) ... (statement n)
> >>> assert foo, 'Errormsg'


I assume you mean to call foo, because if you don't, it will surely be
true and the assert will just never trigger.

Now, calling expressions expressions, rather than very confusingly
statements, can you explain how the semantics of this, with foo being
called, would differ from those of

assert exp1 and exp2 and exp3 ... and expN, 'errormsg'

???


> My proposal is to add the following syntax to the language:
>
> >>> assert (statement 1), (statement 2), ... (statement n), 'Errormsg'


Again: can you explain how the semantics of this, would differ from
those of:

assert exp1 and exp2 and exp3 ... and expN, 'errormsg'

???

> Or, if the user prefers, the traditional comma rules also applies:


There is no such "traditional" rule (or rules) in Python. Both a
statement and an expression can perfectly well end in a comma; the comma
does NOT imply any kind of continuation.


Alex
 
Reply With Quote
 
 
 
 
Andrew Koenig
Guest
Posts: n/a
 
      11-06-2004
"Fábio Mendes" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...

> I'm sorry if it's an replicate. Either my e-mail program is messing with
> things or the python-list sent my msg to /dev/null. I couldn't find
> anything related in previous PEP's, so here it goes a very early draft
> for a new "assert" syntax:


Do you have a use case? That is, can you give a plausible example that
shows why your proposal would be useful and how it would work?


 
Reply With Quote
 
John Roth
Guest
Posts: n/a
 
      11-07-2004

"Fábio Mendes" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> I'm sorry if it's an replicate. Either my e-mail program is messing with
> things or the python-list sent my msg to /dev/null. I couldn't find
> anything related in previous PEP's, so here it goes a very early draft
> for a new "assert" syntax:
>

[...]
>
> I'm interested to write a formal PEP if I receive good feedback from the
> community, but I never wrote a PEP before, and (the worst problem) my
> english is not so good. Anyone helps?
>
> Thanks,
> Fabio


I see two difficulties with it.

First, you can do the same thing (I think) with a
try block around a sequence of statements and
an assert in the except block. This means you
will need a fairly strong use case based on
convenience to add the syntax to the language.
You will have to show that it will be used a lot.

Second, the statement form has the potential to
cause side effects. There is a very strong
community of thought that says that asserts
are debugging or validation statements that
should not cause any behavior change by
removing them. This can be dealt with by
making it some form of block that has its
own local variables that are discarded on
exit.

John Roth

 
Reply With Quote
 
=?ISO-8859-1?Q?F=E1bio?= Mendes
Guest
Posts: n/a
 
      11-07-2004
> > >>> erromsg = 'Errormsg'
> > >>> assert statement 1, errormsg
> > >>> assert statement 2, 'errormsg
> > >>> (...)
> > >>> assert statement n, errormsg

>
> Why isn't this equivalent? Apart from the fact that you keep, here and
> elsewhere, using 'statement' where you hopefully mean 'expression' --
> you cannot assert a statement, you can only assert an expression.


There is only the conceptually subtle difference that in the 1st you
asserts the whole block of expressions, the second you assert each
expression. They're likely to be the same, probably they will be
equivalent in all cases but I can't backup the truth or falsity of that
statement. The pythonic counterpart involves too much typing and is more
error prone.

> Now, calling expressions expressions, rather than very confusingly
> statements, can you explain how the semantics of this, with foo being
> called, would differ from those of
>
> assert exp1 and exp2 and exp3 ... and expN, 'errormsg'


This is very similar to what I'm proposing, with the only inconvinience
that is uglier to type:

assert \
exp1 and \
exp2 and \
...
expn,
'ErrorMsg'

Instead of:

assert \
exp1,
exp2,
...
expn,
'Errormsg'

Well, I realize I didn't expressed my thoughts very clearly and that
it's indeed a very minor change in python's syntax. It won't let anyone
does anything new, IFAIK, but it makes a common pattern of code a little
more beautiful, (and why not? more expressive). If one consider the fact
that it won't break old code (only in one very unlikely case) I don't
see it as a completely unreasonable suggestion. Other people may think
differently though.

Thanks,
Fabio
 
Reply With Quote
 
=?ISO-8859-1?Q?F=E1bio?= Mendes
Guest
Posts: n/a
 
      11-07-2004
> I see two difficulties with it.
>
> First, you can do the same thing (I think) with a
> try block around a sequence of statements and
> an assert in the except block. This means you
> will need a fairly strong use case based on
> convenience to add the syntax to the language.
> You will have to show that it will be used a lot.


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.

Thanks,
Fabio
 
Reply With Quote
 
Raymond Hettinger
Guest
Posts: n/a
 
      11-07-2004
[Fábio Mendes]
> This is very similar to what I'm proposing, with the only inconvinience
> that is uglier to type:
>
> assert \
> exp1 and \
> exp2 and \
> ...
> expn,
> 'ErrorMsg'
>
> Instead of:
>
> assert \
> exp1,
> exp2,
> ...
> expn,
> 'Errormsg'
>
> Well, I realize I didn't expressed my thoughts very clearly and that
> it's indeed a very minor change in python's syntax. It won't let anyone
> does anything new, IFAIK, but it makes a common pattern of code a little
> more beautiful, (and why not? more expressive). If one consider the fact
> that it won't break old code (only in one very unlikely case) I don't
> see it as a completely unreasonable suggestion. Other people may think
> differently though.


The odds of Guido accepting this proposal are about zero. As you say, it
doesn't do anything new, but it does require altering the grammar. Besides,
TOOWTDI.

Also, Guido tends to not be persuaded by arguments about "too much typing".
This is doubly true is you're talking about replacing an "and" with a comma (big
whoop).

Also, one of the existing alternatives is quite readable:

err = 'Errormsg'
assert exp1, err
assert exp2, err
assert exp3, err

The alternative has the advantage that a failure will point to the exact
expression that failed. The disadvantage is the repetition of the error
message; however, I disagree that your use case is common. Instead, it is
likely more advantageous to have different error messages for each expression.
For example, the following comes from the post condition checks in QR matrix
decomposition:

assert Q.tr().mmul(Q)==eye(min(m,n)), "Q is not orthonormal"
assert isinstance(R,UpperTri), "R is not upper triangular"
assert R.size==(m,n), "R is does not match the original dimensions"
assert Q.mmul(R)==self, "Q*R does not reproduce the original matrix"

One could link all of these by an "and" or the proposed comma, but then you
end-up with a single, less informative error message, "The QR decomposition
bombed, but I won't tell you why ".


Raymond Hettinger


 
Reply With Quote
 
Paul Rubin
Guest
Posts: n/a
 
      11-07-2004
Some time ago I found myself proposing a new "Validate" statement,
which would work exactly like "assert", except:

1) it would throw a ValidationError instead of AssertionError
if the condition failed

2) it would NOT be turned into a no-op by the optimizing compiler.

The purpose is runtime validation of user data, rather than sanity
checking the program logic. Example: I keep finding myself writing
code like:

x = float(raw_input('Enter a positive number: '))
assert x > 0, 'number wasn't positive'

This is incorrect because the assert statement is not guaranteed to be
executed. I propose to say instead,

validate x > 0, 'number wasn't positive'

which would do the right thing.

This proposal was reasonably well received when I've posted it before,
but I don't remember if there was any conclusion, and there was no
follow-up. Since we're again talking about PEP's regarding the assert
statement, should I try to put one together for this, in my copious
(hah) free time?
 
Reply With Quote
 
=?ISO-8859-1?Q?F=E1bio?= Mendes
Guest
Posts: n/a
 
      11-07-2004
> Some time ago I found myself proposing a new "Validate" statement,
> which would work exactly like "assert", except:
>
> 1) it would throw a ValidationError instead of AssertionError
> if the condition failed
>
> 2) it would NOT be turned into a no-op by the optimizing compiler.
>

[...]
This sounds great. I like the validate syntax. This also sounds very
useful to me. If it doesn't go mainstream, it should, at least be a
parameter controlled at runtime:

>>> import validate
>>> validate.always_compile_assertions = True # this name sucks! I know!


Ideally, for me, python would support a decent DPC-like semantics:

>>> class foo_bar:
>>> contract, 'invariant':
>>> assert (something always true), 'Errormsg1'
>>> assert (more imutable truths), 'Errormsg2'
>>>
>>> def foo(self, var1, var2):
>>> contract, 'pre':
>>> # var1 and var2 are avaiable in this scope
>>> assert expr, 'Error string1'
>>> assert expr1, expr2, 'Error string2'
>>>
>>> contract, 'pos':
>>> # var1, var2, avaiable. 'old' is 'self' before calling foo
>>> # foo.return stands for the output of function foo (or None)
>>> # foo.error is any the exception the function had trown
>>> assert self.bar > old.bar
>>> assert foo == some result, 'Error string'
>>> if foo.error == some Exception:
>>> assert (condition to trow that exception), 'Error'
>>>
>>> (function implementation)



The (python) implementation of this syntax can be something like this.
If dbc is enable, foo method becames:

>>> def foo(self, var1, var2):
>>> try:
>>> contract invariant block
>>> ...
>>> except AssertionError, x:
>>> contractViolations.log('invariant', x)
>>>
>>> try:
>>> pre contract block
>>> ...
>>> except AssertionError, x:
>>> contractViolations.log('pre', x)
>>> try:
>>> foo.value = __old_foo(var1, var2)
>>> finally error, error_msg:
>>> if error: foo.value = None
>>> foo.error = error
>>> try:
>>> post contract block
>>> except AssertionError, x:
>>> contractViolations.log('pos', x)
>>> if error and not contract.fail_silently:
>>> raise error, error_msg


The program executes normally, then, if non fatal errors happens,
contracViolations.report() will print a nice formated report of what was
violated, similar to what unittest module does. This is not pure DBC I
guess, but is nice.

Thanks,
Fabio
 
Reply With Quote
 
=?ISO-8859-1?Q?F=E1bio?= Mendes
Guest
Posts: n/a
 
      11-07-2004
> The alternative has the advantage that a failure will point to the exact
> expression that failed. The disadvantage is the repetition of the error
> message; however, I disagree that your use case is common. Instead, it is
> likely more advantageous to have different error messages for each expression.
> For example, the following comes from the post condition checks in QR matrix
> decomposition:
>
> assert Q.tr().mmul(Q)==eye(min(m,n)), "Q is not orthonormal"
> assert isinstance(R,UpperTri), "R is not upper triangular"
> assert R.size==(m,n), "R is does not match the original dimensions"
> assert Q.mmul(R)==self, "Q*R does not reproduce the original matrix"
>
> One could link all of these by an "and" or the proposed comma, but then you
> end-up with a single, less informative error message, "The QR decomposition
> bombed, but I won't tell you why ".
>

You have a good point here. Maybe what I proposed is only a distraction.
We don't want a syntax tailored to every sittuation as it will serve
only for showcase selected programs that express the full elegance of
the language, but to the programmer, it gains the burden of memorizing
the 100 and so operators that makes the language very expressive. Of
course each person will develop a personal dialect, which will make his
code very expressive in a specific domain, but he'll talk to
nobodyelse... For that we have perl. So I guess i'm off this thread, but
someone pointed a PEP for a 'validate' statement which still holds. At
least it will help to elucidate the somewhat confusing meaning of the
assert statement. (you shouldn't use it at runtime?? which level of
optimizations disable it?).

Fabio
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
To assert or not to assert... ImpalerCore C Programming 79 05-17-2010 12:47 PM
Is there a standard "assert" idiom in Ruby? Kenneth McDonald Ruby 8 08-03-2007 12:18 AM
assert 0, "foo" vs. assert(0, "foo") Thomas Guettler Python 3 02-23-2005 07:53 PM
assert(x) and '#define ASSERT(x) assert(x)' Alex Vinokur C Programming 5 11-25-2004 08:48 PM
RE: remove assert statement (Was: Re: PEP new assert idiom) Robert Brewer Python 1 11-07-2004 06:53 PM



Advertisments