What c.l.py's opinions about Soft Exception?

Lie Lie.1296 at gmail.com
Tue Mar 11 11:14:54 CET 2008


On Mar 11, 2:18 am, "Diez B. Roggisch" <de... at nospam.web.de> wrote:
> > The problem with callbacks is that it works only for a small amount of
> > callbacks, it'd be too messy to have twenty different callbacks.
> > And the ultimate problem with callbacks is that we can't determine
> > from the outside whether the operation should continue or breaks at
> > the point of the callback without some messy trick.
>
> > We can't always determine whether we want to do this:
> > def somefunc(argA, argB, callback = DO_NOTHING):
> >     if argA == argB:
> >         callback()
>
> > or this:
> > def somefunc(argA, argB, callback = DO_NOTHING):
> >     if argA == argB:
> >         callback()
> >         return
>
> > perhaps we could do this:
> >     if argA == argB:
> >         if callback() == True: return
>
> > but that's so much extra codes written and would've been too messy to
> > write.
>
> > And actually this isn't a rare cases, and in fact is very common. It's
> > just that most cases that can be more cleanly written in
> > SoftException, can usually be handled in different ways, using tricks
> > that range from subtle to messy (like callbacks).
>
> I fail to see how your arguments follow.
>
> Regarding the number of callbacks: you can as well pass an object that
> has several methods to call.

If you passed an object that has several methods to call (using tuple
or list) and you want to handle several softexceptions and ignore some
others, you must still pass an empty methods to the one you want to
ignore, cluttering the caller's code by significant degree:

    def somefunc(a, b, callback = (DO_NOTHING, DO_NOTHING, DO_NOTHING,
DO_NOTHING)):
        if a == 0: raise callback(0)
        try:
            a += b
        except ZeroDivisionError:
            raise callback(1)
        if a <= 0: raise callback(2)
        raise callback(3)
        return a

    somefunc(a, b, (callbackzero, DO_NOTHING, callbacktwo,
DO_NOTHING))

if instead we use dict, well, we know how <inverse>convenient</
inverse> dict's syntax is for a lot of manual data entry.

    ## imagine if we want to handle five or more callbacks
    somefunc(a, b, {callbackzero:handlerzero,
callbacktwo:handlertwo})

> And the above example can easily be accomplished with "normal"
> exceptions, like this:
>
> def toplelevel():
>      def callback(a, b):
>          if a == b:
>             raise InterruptException()
>      try:
>           work(callback)
>      except InterruptException:
>           pass
>
> def work(callback=callback):
>      a = 10
>      b = 20
>      callback(a, b)

That's why I said most things that can be more cleanly handled by
SoftException can usually be handled in other forms, although in a
more cluttered way.

That could be more cleanly written in SoftException as:
    def work():
        a = 10
        b = 20
        raise Equal(a, b)

    def toplevel():
        try:
            work()
        except Equal, args:
            a, b = args
            if a == b:
                raise InterruptException

OR ALTERNATIVELY (Which one's better depends on the purpose, generally
the one below is better, but the one in the above is more flexible,
yet a bit less convenient to use)

    def work():
        a = 10
        b = 20
        if a == b: raise Equal

    def toplevel():
        try:
            work()
        except Equal:
            raise InterruptException

The reason why SoftException is useful is similar to the reason why
for-loop and while <condition> is useful. AFAIK, all looping cases can
be handled only by a blind loopers (a.k.a. while True:) and break, but
a blind loopers is very inconvenient to use, and for-loop and while
<condition> simplifies a lot of codes a lot. Exactly the same reason
why SoftException is useful.

> And even more: the callback-approach can do things like this:
>
> a, b = callback(a,b)
>
> to change values, which makes it superior to SoftExceptions - unless I
> missed it's ability to capture context.

If there is a syntax support, you could also make "resume" able to
transfer values:

    def somefunc(a, b):
        if a == b: a, b = raise Equal(a, b)

    def toplevel():
        try:
            somefunc(10, 20)
        except Equal, args:
            a, b = args[0], args[1] + 1
            resume a, b

On Mar 11, 5:18 am, "Diez B. Roggisch" <de... at nospam.web.de> wrote:
> How would that differ from something like this:
>
> with add_soft_handler(SoftException):
>     invoke_something()
>
> ... # deep down in code
>
> raise_soft(SoftException())
>
> The implementation of add_soft_handler and raise_soft is trivial - a bit
> of thread-local storage and a stack.

Perhaps you meant:
    raise_soft(SoftException)

cause SoftException() may have side effects if called greedily

That could be done, but when raise_soft() returns, it returns to the
code that raises it so it must be 'break'en:

    def caller(a, b):
        if a == b:
            raise_soft(SoftException)
            break

but this makes SoftException must break everytime, which make it lost
its original purpose, so you have to add return code to raise_soft
whether you want to break it or not:

    def caller(a, b):
        if a == b:
            if raise_soft(SoftException):
                break

Compare to:
    def caller(a, b):
        if a == b:
            raise SoftException

And this also makes it impossible to have state-changing behavior
without some other weirder tricks



More information about the Python-list mailing list