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

Lie Lie.1296 at gmail.com
Sun Mar 9 04:30:51 EDT 2008


On Mar 9, 12:05 pm, Kay Schluehr <kay.schlu... at gmx.net> wrote:
> On 9 Mrz., 04:51, Lie <Lie.1... at gmail.com> wrote:
>
> > A more through implementation would start from the raiser inspecting
> > the execution stack and finding whether there are any try block above
> > it, if no try block exist it pass silently and if one exist it will
> > check whether it have a matching except clause. This also circumvents
> > a problem that simple implementation have, as described below.
>
> This will not be easy in particular in the presence of inheritance and
> dynamism. There is no way to statically decide whether an exception
> BException has the type AException and will be caught by the except
> clause in
>
> try:
>     BLOCK
> except AException, e:
>     print "SoftException %s caught"%e



> A feasible solution was to invert the try...except statement and
> creating a continuation.
>
> catch AException, a:
>    print "SoftException A: %s"%a
> catch BException , b:
>    print "SoftException B: %s"%b
> ...
> in:
>    BLOCK
>
> Here each SoftException is raised initially when a catch clause is
> entered and a continuation is created that returns to the catch block
> of the raised SoftException if required. When a SoftException is
> raised within BLOCK a lookup will be made and if a corresponding
> SoftException was found that was raised by a catch-clause the current
> control flow will be suspended and the continuation is called.

I'd rather want to avoid any syntax changes, as I wished that Soft
Exception can be added to the language silently[1] so that new
programmers doesn't _need_ to know about it (although knowing it could
change the way they write codes to be more structured and simple).

[1] Definition of silently: Codes that aren't aware of this
functionality shouldn't break. Adding new syntax usually means adding
keywords, making possible break in current program.

On Mar 9, 12:30 pm, Steven D'Aprano <st... at REMOVE-THIS-
cybersource.com.au> wrote:
> On Sat, 08 Mar 2008 19:51:24 -0800, Lie wrote:
> > Soft Exception
> > What is "Soft Exception"?
> > Soft Exception is an exception that if is unhandled, pass silently as if
> > nothing happened. For example, if a variable turns into NoneType, it'll
> > raise Soft Exception that it have become NoneException, programmers that
> > wants to handle it can handle it with a try...except block while
> > programmers that doesn't care about it (or know it won't be a problem to
> > his code) can just leave the code as it is.
>
> > Soft Exception differs from Hard Exceptions (the regular Exception) in a
> > way that Hard Exception must be handled at all cost or the program will
> > be terminated while Soft Exception allow programmers not to handle it if
> > they don't want to.
>
> I don't think that there are very many cases where exceptions can be
> ignored safely. There are two main reasons for using exceptions:
>
> (1) Signaling an exceptional event.

In that case, programmers might decide whether to raise Soft or Hard
Exception. Hard Exception is much preferred.

> (2) An error occurred.

Which must always be handled with Hard Exception.

Adding another thing
(3) Informing codes above it about what's currently happening inside,
the thing is just a mundane report that might be useful to codes above

Which might be a useful place to use SoftExceptions

> I can't think of many cases where you would wish to ignore either, and
> just continue processing. The only examples I can think of are in loops,
> where you are doing the same thing over and over again with just a little
> change, and you wish to skip any problematic data, e.g.:
>
> def plot_graph(func, domain):
>     for x in domain:
>         plot(x, func(x))
>
> If an error occurs in plot() for one particular x value, you would want
> to ignore it and go on to the next point. But that's easy enough to do
> with a regular try...except block.

No, you're misunderstanding the purpose of Soft Exception, it's not
for silencing errors and not so much for exceptional cases. It's for
the more mundane tasks such as:

from __future__ import division

class SomeNumeric(object):
    def __div__(a, b):
        if b == 0: raise ZeroDivisionError  ## Hard Exception, don't
ignore me!
        if a == 0: raise ZeroNumerator      ## Soft Exception
        f = a / b
        i = a // b
        if f == float(i):
            raise IntegerDivision  ## Soft Exception
            return a // b
        else:
            raise FloatDivision    ## Soft Exception
            return a / b

Most people can ignore the ZeroNumerator, IntegerDivision, and
FloatDivision exceptions (warnings) because they're excessive and
unnecessary, but some people might want to catch them and do something
else (especially ZeroNumerator). Practicle example, far below.

The example is actually quite bad at demonstrating the purpose of Soft
Exception as it is very simple while Soft Exception is generally more
useful in complex operations. But I want to avoid giving complex
examples since it'll be more difficult to explain the complex examples
instead of the simple examples.

> Simply put, you're suggesting the following two alternatives:
>
> Hard Exceptions: terminate the program unless explicitly silenced
> Soft Exceptions: pass silently unless explicitly caught
>
> In this case, I agree with the Zen of Python ("import this"):
>
> Errors should never pass silently.
> Unless explicitly silenced.

That's what sloppy programmers do, silently pass errors. OTOH, Soft
exceptions are not used for errors (perhaps the wording can be better
phrased: must not be used for errors), they're used for events that
some might have interest in, but some would consider it as normal.
That's why I mentioned to think of it as a Warning. Operations that
raise Soft Exceptions should be able to run normally even when the
exception isn't handled (although it might generate garbage out that
can be handled at later time).

> The cost of explicitly silencing exceptions is tiny, the risk of misuse
> of Soft Exceptions is very high, and the benefit of them is negligible.

Perhaps relabeling it as Warning, and renaming raise SoftException as
give Warning might make it more acceptable?
And I agree that the probability for misuse is quite high, but the
benefits is also quite high, it's just that you can't see it since
you're not used to using such exceptions. The benefit of
SoftExceptions lies mostly on the regular programmings tasks, not the
exceptional programming tasks

Practical Example:
This example takes _case ideas_ from this simple gravity simulator
http://www.pygame.org/project/617/ BUT _no line of code is taken from
it_. I only give this link so you can easily know what the case is
about without lengthy explanation.

A particle machine.
The particle machine calculates gravity created by the particles in a
field. Additionaly, it clumps together two particles that happens to
be near enough (less than the sum of their radiuses).

The force two particle is expressing to each other is calculated with:
    def calculateforce(P1, P2):
        return (P1.mass - P2.mass) / distance(P1, P2)

and this is done to every particle in the field against the current
particle.

And the distance is calculated by:
    def distance(P1, P2)
        return (P1.X - P2.X) ** 2 - (P1.Y - P2.Y) ** 2

The problem happens when the distance is small enough and we want to
clump them together.

A possible solution to this problem might be to check whether distance
is less than P1.radius + P2.radius in the calculateforce.
But, this obfuscate the code since we have to separate distance
calculation from the main formula (see !s), and this also insist that
clumping be done on force calculation level (see @s), shortly this
piece of code is plain bad:
    def distance(P1, P2):
        return (P1.X - P2.X) ** 2 - (P1.Y - P2.Y) ** 2

    def calculateforce(P1, P2):
        ## Separating this dist calculation into its own line is
        ## necessary if we want to check the value of dist
        ## Personally I think that's a bit obfuscated.
        ## Well known formulas should be kept to one line if possible
!       dist = distance(P1, P2)

        if dist <= P1.radius + P2.radius:
            ## Calling clump() here is bad, because
            ## there are occasions where we only want to
            ## calculate force but doesn't want to
            ## clump it
@           clump(P1, P2)
        else:
!           return (P1.mass - P2.mass) / dist

    ## Codes calling calculateforce()
    # Note: this code is located inside a loop

    F = calculateforce(P1, P2)
    # Do something else, acceleration calculation, movement
calculations, etc


A better refactoring would be like this, but this requires calculating
distance twice (see !s):
    def distance(P1, P2):
        return (P1.X - P2.X) ** 2 - (P1.Y - P2.Y) ** 2

    def calculateforce(P1, P2):
        ## Here distance is calculated once
!       return (P1.mass - P2.mass) / distance(P1, P2)

    ## Codes calling calculateforce()
    # Note: this code is located inside a loop

    ## Here distance is calculated again
!   if distance(P1, P2) <= P1.radius + P2.radius:
        clump(P1, P2)
        break
    F = calculateforce(P1, P2)
    # Do something else, acceleration calculation, movement
calculations, etc


A much better solution would be to use SoftException
    def distance(P1, P2):
        D = (P1.X - P2.X) ** 2 - (P1.Y - P2.Y) ** 2
        if D <= P1.radius + P2.radius: raise Collision
        return D

    def calculateforce(P1, P2):
        try:
            F = (P1.mass - P2.mass) / distance(P1, P2)
        except Collision:
            raise

    ## Codes calling calculateforce()
    # Note: this code is located inside a loop
    try:
        F = calculateforce(P1, P2)
    except Collision:
        clump(P1, P2)
        break  # Calculate the next particle pair
    else:
        # Do something else, acceleration calculation,
        # speed calculation, movement calculations, etc

This results in a cleaner code. And it also allow _other part of
codes_ that uses calculate distance and force to easily ignore or
handle the Collision Exception. If this code had used Hard Exception,
other codes would have to explicitly silence the exception or the
program terminates. That would be too much since Collision is
technically not an Error, but just a normal events that you might be
interested to know. Soft Exception allows events of interest to be
noticed or be ignored depending on the requirement.

It's like a notice board: In the notice board, there are notices about
the Maths Test next week, which you must not ignore (Hard Exception),
but there are also notices about Part-time Job Advertisement, if
you're interested about it you can look at it further, else you could
just ignore it and do nothing (Soft Exception)



More information about the Python-list mailing list