PEP 352: Required Superclass for Exceptions

Well, I am at it again, but this time Guido is a co-conspirator. We wrote a PEP that introduces BaseException and moves KeyboardInterrupt and SystemExit. Even if you followed the discussion for PEP 348 you should read the PEP since I am sure there will be something that someone doesn't like, such as the transition plan or how I didn't use British English throughout. =) Anyway, as soon as the cron job posts the PEP to the web site (already checked into the new svn repository) have a read and start expounding about how wonderful it is and that there is no qualms with it whatsoever. =) -Brett

Brett Cannon wrote:
Anyway, as soon as the cron job posts the PEP to the web site (already checked into the new svn repository) have a read and start expounding about how wonderful it is and that there is no qualms with it whatsoever. =)
You mean aside from the implementation of __getitem__ being broken in BaseException*? ;) Aside from that, I actually do have one real problem and one observation. The problem: The value of ex.args The PEP as written significantly changes the semantics of ex.args - instead of being an empty tuple when no arguments are provided, it is instead a singleton tuple containing the empty string. A backwards compatible definition of BaseException.__init__ would be: def __init__(self, *args): self.args = args self.message = '' if not args else args[0] The observation: The value of ex.message Under PEP 352 the concept of allowing "return x" to be used in a generator to mean "raise StopIteration(x)" would actually align quite well. A bare "return", however, would need to be changed to translate to "raise StopIteration(None)" rather than its current "raise StopIteration" in order to get the correct value (None) into ex.message. Cheers, Nick. * (self.args[0] is self.message) due to the way __init__ is written, but __getitem__ assumes self.message isn't in self.args) -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.blogspot.com

On 10/28/05, Nick Coghlan <ncoghlan@gmail.com> wrote:
Brett Cannon wrote:
Anyway, as soon as the cron job posts the PEP to the web site (already checked into the new svn repository) have a read and start expounding about how wonderful it is and that there is no qualms with it whatsoever. =)
You mean aside from the implementation of __getitem__ being broken in BaseException*? ;)
Are you clairvoyant?! The cronjob wass broken due to the SVN transition and the file wasn't on the site yet. (Now fixed BTW.) Oh, and here's the URL just in case: http://www.python.org/peps/pep-0352.html
Aside from that, I actually do have one real problem and one observation.
The problem: The value of ex.args
The PEP as written significantly changes the semantics of ex.args - instead of being an empty tuple when no arguments are provided, it is instead a singleton tuple containing the empty string.
A backwards compatible definition of BaseException.__init__ would be:
def __init__(self, *args): self.args = args self.message = '' if not args else args[0]
But does anyone care? As long as args exists and is a tuple, does it matter that it doesn't match the argument list when the latter was empty? IMO the protocol mostly says that ex.args exists and is a tuple -- the values in there can't be relied upon in pre-2.5-Python. Exceptions that have specific information should store it in a different place, not in ex.args.
The observation: The value of ex.message
Under PEP 352 the concept of allowing "return x" to be used in a generator to mean "raise StopIteration(x)" would actually align quite well. A bare "return", however, would need to be changed to translate to "raise StopIteration(None)" rather than its current "raise StopIteration" in order to get the correct value (None) into ex.message.
Since ex.message is new, how can you say that it should have the value None? IMO the whole idea is that ex.message should always be a string going forward (although I'm not going to add a typecheck to enforce this). -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On 10/28/05, Guido van Rossum <guido@python.org> wrote:
On 10/28/05, Nick Coghlan <ncoghlan@gmail.com> wrote:
Brett Cannon wrote:
Anyway, as soon as the cron job posts the PEP to the web site (already checked into the new svn repository) have a read and start expounding about how wonderful it is and that there is no qualms with it whatsoever. =)
You mean aside from the implementation of __getitem__ being broken in BaseException*? ;)
Are you clairvoyant?! The cronjob wass broken due to the SVN transition and the file wasn't on the site yet. (Now fixed BTW.) Oh, and here's the URL just in case: http://www.python.org/peps/pep-0352.html
Nick got the python-checkins email and then read the PEP from the repository (or at least that is what I assume since that is how Neal managed to catch the PEP literally in under 5 minutes after checkin).
Aside from that, I actually do have one real problem and one observation.
The problem: The value of ex.args
The PEP as written significantly changes the semantics of ex.args - instead of being an empty tuple when no arguments are provided, it is instead a singleton tuple containing the empty string.
A backwards compatible definition of BaseException.__init__ would be:
def __init__(self, *args): self.args = args self.message = '' if not args else args[0]
But does anyone care? As long as args exists and is a tuple, does it matter that it doesn't match the argument list when the latter was empty? IMO the protocol mostly says that ex.args exists and is a tuple -- the values in there can't be relied upon in pre-2.5-Python. Exceptions that have specific information should store it in a different place, not in ex.args.
Looking at http://docs.python.org/lib/module-exceptions.html , it looks like Guido is right. All it ever says is that it is a tuple and that any passed-in arguments go into 'args'; nothing about its default value if no arguments are passed in. But I personally have no qualms changing it if people want it, so -0 from me on making it more backwards-compatible.
The observation: The value of ex.message
Under PEP 352 the concept of allowing "return x" to be used in a generator to mean "raise StopIteration(x)" would actually align quite well. A bare "return", however, would need to be changed to translate to "raise StopIteration(None)" rather than its current "raise StopIteration" in order to get the correct value (None) into ex.message.
Since ex.message is new, how can you say that it should have the value None? IMO the whole idea is that ex.message should always be a string going forward (although I'm not going to add a typecheck to enforce this).
My feeling exactly on 'message'. -Brett

Brett Cannon wrote:
On 10/28/05, Guido van Rossum <guido@python.org> wrote: Nick got the python-checkins email and then read the PEP from the repository (or at least that is what I assume since that is how Neal managed to catch the PEP literally in under 5 minutes after checkin).
Actually, when you first check a PEP in, the diff includes the entire text of the PEP - so I just read the python-checkins email :)
But does anyone care? As long as args exists and is a tuple, does it matter that it doesn't match the argument list when the latter was empty? IMO the protocol mostly says that ex.args exists and is a tuple -- the values in there can't be relied upon in pre-2.5-Python. Exceptions that have specific information should store it in a different place, not in ex.args.
Looking at http://docs.python.org/lib/module-exceptions.html , it looks like Guido is right. All it ever says is that it is a tuple and that any passed-in arguments go into 'args'; nothing about its default value if no arguments are passed in.
But I personally have no qualms changing it if people want it, so -0 from me on making it more backwards-compatible.
I agree changing the behaviour is highly unlikely to cause any serious problems (mainly because anyone *caring* about the contents of args is rare), the current behaviour is relatively undocumented, and the PEP now proposes deprecating ex.args immediately, so Guido's well within his rights if he wants to change the behaviour. I was merely commenting from the 'its an unnecessary change to existing behaviour' angle, since the backwards compatible version gives the same behaviour of the new ex.message API as the version in the PEP, while leaving the now-deprecated ex.args API behaviour identical to that in Python 2.4. In other words, I'm looking for a *benefit* that comes from the behavioural change, rather than a 'but the current behaviour is undocumented anyway' response. If there's no actual benefit in breaking it, then why break it? :)
The observation: The value of ex.message
Under PEP 352 the concept of allowing "return x" to be used in a generator to mean "raise StopIteration(x)" would actually align quite well. A bare "return", however, would need to be changed to translate to "raise StopIteration(None)" rather than its current "raise StopIteration" in order to get the correct value (None) into ex.message. Since ex.message is new, how can you say that it should have the value None? IMO the whole idea is that ex.message should always be a string going forward (although I'm not going to add a typecheck to enforce this).
My feeling exactly on 'message'.
I'm talking about the specific context of the behaviour of 'return' in generators, not on the behaviour of ex.message in general. For normal exceptions, I agree '' is the correct default. For that specific case of allowing a return value from generators, and using it as the message on the raised StopIteration, *then* it makes sense for "return" to translate to "raise StopIteration(None)", so that generators have the same 'default return value' as normal functions. There's a reason I said it was just an observation - it has no effect on PEP 352 itself, only on a *different* syntax extension that hasn't even been officially suggested in a PEP (only mentioned in passing when discussing PEP 342). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.blogspot.com

On 10/28/05, Nick Coghlan <ncoghlan@gmail.com> wrote:
Brett Cannon wrote:
On 10/28/05, Guido van Rossum <guido@python.org> wrote: Nick got the python-checkins email and then read the PEP from the repository (or at least that is what I assume since that is how Neal managed to catch the PEP literally in under 5 minutes after checkin).
Actually, when you first check a PEP in, the diff includes the entire text of the PEP - so I just read the python-checkins email :)
But does anyone care? As long as args exists and is a tuple, does it matter that it doesn't match the argument list when the latter was empty? IMO the protocol mostly says that ex.args exists and is a tuple -- the values in there can't be relied upon in pre-2.5-Python. Exceptions that have specific information should store it in a different place, not in ex.args.
Looking at http://docs.python.org/lib/module-exceptions.html , it looks like Guido is right. All it ever says is that it is a tuple and that any passed-in arguments go into 'args'; nothing about its default value if no arguments are passed in.
But I personally have no qualms changing it if people want it, so -0 from me on making it more backwards-compatible.
I agree changing the behaviour is highly unlikely to cause any serious problems (mainly because anyone *caring* about the contents of args is rare), the current behaviour is relatively undocumented, and the PEP now proposes deprecating ex.args immediately, so Guido's well within his rights if he wants to change the behaviour.
I was merely commenting from the 'its an unnecessary change to existing behaviour' angle, since the backwards compatible version gives the same behaviour of the new ex.message API as the version in the PEP, while leaving the now-deprecated ex.args API behaviour identical to that in Python 2.4.
In other words, I'm looking for a *benefit* that comes from the behavioural change, rather than a 'but the current behaviour is undocumented anyway' response. If there's no actual benefit in breaking it, then why break it? :)
The benefit for me was that the code kept the 'message' argument and thus, in my mind, made it much more obvious that 'mesage' and 'args' are different. But I think I have a much more reasonable solution that lets me keep the 'message' argument explicit. It also let me use the conditional operator to simplify the code more. So I went ahead and made it the more backwards-compatible.
The observation: The value of ex.message
Under PEP 352 the concept of allowing "return x" to be used in a generator to mean "raise StopIteration(x)" would actually align quite well. A bare "return", however, would need to be changed to translate to "raise StopIteration(None)" rather than its current "raise StopIteration" in order to get the correct value (None) into ex.message. Since ex.message is new, how can you say that it should have the value None? IMO the whole idea is that ex.message should always be a string going forward (although I'm not going to add a typecheck to enforce this).
My feeling exactly on 'message'.
I'm talking about the specific context of the behaviour of 'return' in generators, not on the behaviour of ex.message in general. For normal exceptions, I agree '' is the correct default.
For that specific case of allowing a return value from generators, and using it as the message on the raised StopIteration, *then* it makes sense for "return" to translate to "raise StopIteration(None)", so that generators have the same 'default return value' as normal functions.
There's a reason I said it was just an observation - it has no effect on PEP 352 itself, only on a *different* syntax extension that hasn't even been officially suggested in a PEP (only mentioned in passing when discussing PEP 342).
Ah, OK. So you just want to make sure that at the generator level that the bytecode (or the ceval loop, not sure where the change would need to be made) that the StopIteration be raised with an explicit 'message' argument of None. Which obviously does not directly affect PEP 352, but should be considered as a possible change. That makes sense to me and I have no trouble with that, but that is partially because I don't have to make that change. =) -Brett

[Trying to cut this short... We have too many threads for this topic. :-( ] On 10/28/05, Nick Coghlan <ncoghlan@gmail.com> wrote: [on making args b/w compatible]
I agree changing the behaviour is highly unlikely to cause any serious problems (mainly because anyone *caring* about the contents of args is rare), the current behaviour is relatively undocumented, and the PEP now proposes deprecating ex.args immediately, so Guido's well within his rights if he wants to change the behaviour.
I take it back. Since the feature will disappear in Python 3.0 and is maintained only for b/w compatibility, we should keep it as b/w compatible as possible. That means it should default to () and always have as its value exactly the positional arguments that were passed. OTOH, I want message to default to "", not to None (even though it will be set to None if you explicitly pass None as the first argument). So the constructor could be like this (until Python 3000): def __init__(self, *args): self.args = args if args: self.message = args[0] else: self.message = "" I think Nick proposed this before as well, so let's just do this.
I'm talking about the specific context of the behaviour of 'return' in generators, not on the behaviour of ex.message in general. For normal exceptions, I agree '' is the correct default.
For that specific case of allowing a return value from generators, and using it as the message on the raised StopIteration, *then* it makes sense for "return" to translate to "raise StopIteration(None)", so that generators have the same 'default return value' as normal functions.
I don't like that (not-even-proposed) feature anyway. I see no use for it; it only gets proposed by people who are irked by the requirement that generators can contain 'return' but not 'return value'. I think that irkedness is unwarranted; 'return' is useful to cause an early exit, but generators don't have a return value so 'return value' is meaningless. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On 10/28/05, Guido van Rossum <guido@python.org> wrote:
[Trying to cut this short... We have too many threads for this topic. :-( ]
On 10/28/05, Nick Coghlan <ncoghlan@gmail.com> wrote: [on making args b/w compatible]
I agree changing the behaviour is highly unlikely to cause any serious problems (mainly because anyone *caring* about the contents of args is rare), the current behaviour is relatively undocumented, and the PEP now proposes deprecating ex.args immediately, so Guido's well within his rights if he wants to change the behaviour.
I take it back. Since the feature will disappear in Python 3.0 and is maintained only for b/w compatibility, we should keep it as b/w compatible as possible. That means it should default to () and always have as its value exactly the positional arguments that were passed.
OTOH, I want message to default to "", not to None (even though it will be set to None if you explicitly pass None as the first argument). So the constructor could be like this (until Python 3000):
def __init__(self, *args): self.args = args if args: self.message = args[0] else: self.message = ""
I think Nick proposed this before as well, so let's just do this.
Yeah, but Nick used the conditional operator and I used that. All checked in. -Brett
participants (3)
-
Brett Cannon
-
Guido van Rossum
-
Nick Coghlan