[Python-ideas] except expression

Andrew Barnert abarnert at yahoo.com
Thu Feb 13 20:39:05 CET 2014


On Feb 13, 2014, at 10:30, spir <denis.spir at gmail.com> wrote:

> On 02/12/2014 10:02 PM, Ram Rachum wrote:
>> Hi,
>> 
>> Here's an idea that would help shortening code. Allow a ternary expression
>> based on except, like so:
>> 
>>     first_entry = entries[0] except IndexError else None
>>     item = my_queue.get() except queue.Empty else None
>>     response_text = request('http://whatever.com').text except HttpError
>> else "Can't access data"
>> 
>> Aside from the fact that this would be a big grammar addition, a big
>> problem here is the usage of the `else` keyword, that when used with except
>> usually means "what would happen if there wasn't an exception" and here
>> means the opposite. But I couldn't think of a nicer syntax.
>> 
>> I realize that this is a big change and that most people would be opposed
>> to this... But I guess I just wanted to share my idea :)
> 
> After some considerations, it seems we reached the point of generalising the idea to:
>    * provide a builtin way to indicate a special value for the special cases where
>      the standard value's expression would raise an exception
> As Nick Coghlan shows in another post, this is in fact close to a builtin way to deal with potentially failing functions, in general (below 'op'):
> 
>    def _helper(op, exc, make_default):
>        try:
>            return op()
>        except exc:
>            return make_default()
> 
>    x = _helper(op, Exception, make_default)
> 
> However, this only applies to the case of functions properly speaking (which purpose is computing a product). What about 'actions', meaning procedures that perform an effect? Take the case of count-words for instance, where (in python) when encoutering a word one would add 1 to its count in a dict which keys are the words. On first encounter, there no entry yet for that word. We could check "word in word_counts", but this is doing the dict lookup twice; and catching an exception is worse.

Or you could use setdefault, or use a defaultdict, or, better, a Counter.

And I don't see how you expect to handle this situation with new syntax. You want to do word_counts[word] = 0 in the case where word_counts[word] raised--but you also want to "unfail" that word_counts[word] and provide a value for it to return. That can't be the value of word_counts[word] = 0, because statements don't have values. And, even if you could figure out how to provide the number 0, that wouldn't help anyway, because what you're looking for is an augmented assignment target, and those aren't even values in the language that can be passed around.

> The problem I guess, here and also similarly for functions, is that there is no way for the _client_ (the caller) to control exception throwing; while only the caller knows whether the failing case actually is an error or not, meaning belongs or not the application's logics. Maybe what we need is in fact something like:
> 
>    maybe statement
>        [then
>        dependant-block]
>    else
>        alternative-block
> 
> This is similar in form to exception catching except (sic!) that the actual meaning is to _avoid_ an exception, not to catch it (to avoid it beeing thrown at all).

How do you avoid an exception being thrown? What happens if some function called inside statement tries to raise?

If the answer is "we immediately abort that function, and the rest of the statement, and run the alternative block, then what you've described is just exception handling, as it already exists:

    try:
        statement
    except:
        alternative block
    else:
        dependent block

All you've done is make it less powerful--you can't limit it to specific types, use the value of the exception, try a complex statement, etc.

And I can't think of any other sensible think you could mean here.

> More or less the opposite, in fact. The consequence is that in case of failure no exception is raised, instead the alternative 'else' branch is taken.

Are you just looking to use a flag to shortcut the creation and propagation of an exception object here? If not, in what other way is this semantically different from "an exception is raised, and handled by the alternative branch"?

> Such a construct would work fine for both called actions and functions (which calls are expressions in statement). [1]
> 
> [Similar considerations are evoked in other languages, especially D where I first met them. Generally speaking, people start to realise the seamntic weakness of typical exception catching mecanisms which let no choice or control in the hands of the one who actually knows, namely the client.]
> 
> d
> 
> [1] Practically, this just means adding a test before throwing, and setting a flag instead (the carry would do the job nicely, since it can have no meaning on func return, and is the only copy flag one can set arbitrarily).

And then continuing to execute the rest of the function? Or constructing and returning some value nobody will ever look at?

And what happens if the exception is raised in a function three levels down the stack? How are you going to abort all three of them? 

Really, the only thing you can do when the function tries to raise is to abort the whole function, and all the way up to some piece of code that's looking to deal with the problem. You need a flag that's checked in multiple places in the interpreter to make sure it's propagated correctly.

Which is exactly what raise already does. So you'd just be providing a different kind of exception--one that can't be caught by try/except, but can be caught by maybe. But if you want two kinds of exception, why not many kinds, which any hierarchy you want--which you can already do today, because exception types are classes.

> 
> Thus, the above code translates to:
>    statement
>    if flag:
>        reset flag
>            alternative-block
>        [else:
>        dependant-block]



> 
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/


More information about the Python-ideas mailing list