[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Understanding exceptions [was: Python or Perl for a Debian maintainance project?]



On Sat, Feb 21, 2004 at 11:30:38AM +0100, Florent Rougon wrote:
> Andrew Suffield <asuffield@debian.org> wrote:
> 
> > It was part of an argument against "Python is better because the code
> > is shorter because [exceptions]" - which is only true when you don't
> > handle the errors.
> 
> It seems you don't understand exceptions, so I will try to help you with
> a real-world example (decoding of a network message; names were
> anonymized because the original is closed source):
> 
>   try:
>       if self.header["type"] == 231:
>           pass
>       elif self.header["type"] == 258:
>           appli_str = sock.recv(24)
>           (appli["field name 1"], appli["field name 2"], appli["field name 3"],
>            appli["field name 4"], appli["field name 5"], appli["field name 6"],
>            appli["field name 7"]) = \
>                struct.unpack(">3s2s1s1s15s1s1s", appli_str)
>       elif self.header["type"] == 259:
>           appli_str = sock.recv(48)
>           (appli["field name 2"], appli["field name 8"], appli["field name 9"],
>            appli["field name 10"], appli["field name 4"]) = \
>                struct.unpack(">2s2s6s6s31s1s", appli_str)
>       elif self.header["type"] == 277:
>           appli_str = sock.recv(8)
>           (appli["field name 11"], appli["field name 12"],
>            appli["field name 7"]) = struct.unpack(">4s1s3s", appli_str)
>       elif self.header["type"] == 278:
>           appli_str = sock.recv(4)
>           (appli["field name 13"],) = struct.unpack(">4s", appli_str)
>       else:
>           raise FooProgInvalidReceivedHeaderTypeError(
>               "a header of type %u was received by the FooMachine"
>               % self.header["type"])
>                 
>   except struct.error, val:
>       raise FooProgBodyDecodingError(val)

*Yuck*

This totally needs another layer of abstraction (it's also lacking
sufficient context to even guess at what that would look like;
probably some sort of message description data structure, and a
generic parser).

This is the sort of code that I would make it a high priority to
replace. It's awful.

> So, you see, the code *is* made shorter and clearer by the use of
> exceptions: there is no need to check the "error code" after every
> struct.unpack call;

You're comparing "bad code without exceptions" to "slightly less bad
code with exceptions". The alternative you describe is not a good way
to write this code either.

If I had written it, there would be precisely one unpack call, so
checking the return code would not be an issue.

> there is only one place where it is handled to
> generate a useful exception whose type indicates precisely what happened
> and whose value allows the upper layer to generate a useful error
> message.

I wouldn't consider it adequetely useful. *Why* was there a decoding
error? Which part of the message did not match the expected pattern?
These messages are clearly not simple; figuring it out by hand would
be unpleasent.

And yes, that really is the whole point. You're throwing away useful
information and then saying that it's simpler because you used an
exception.

It is not. It is simpler because it does less.

> No
> need to make the error handling sloppy in order to unobfuscate the
> logic.

Hah.

-- 
  .''`.  ** Debian GNU/Linux ** | Andrew Suffield
 : :' :  http://www.debian.org/ |
 `. `'                          |
   `-             -><-          |

Attachment: signature.asc
Description: Digital signature


Reply to: