Tuesday, August 16, 2011

Python: null values, no values and ellipses

One issue I've found that occasionally crops up in dynamic languages like Python & PHP is the overloaded use of the None/NULL value.

Consider the following terribly contrived example:
class QueryThing:
    handle = None
    
    def __init__(self, db):
        if db and hasattr(db, 'get_handle'):
            self.handle = db.get_handle()

>>> query = QueryThing(some_db)
>>> query.handle
None
Clearly, something has gone wrong here. Either some_db doesn't have a get_handle method, or it does and it failed to return one. But which was it? Returning a value representing the successful result or otherwise None is a very common pattern in Python; a function without an explicit return always has an implicit return None at its end.

So the problem here is there's no distinction between an unset property and an improperly set one. Or even worse: between an unset property and one for which None is a legitimate value.

Python 1.4 added a built-in object - Ellipsis - to provide an extending slicing syntax, primarily used by the 3rd party extension numpy. Nothing within Python handles this slicing syntax natively but any user-written classes can provide their own __getitem__ method which is Ellipsis aware. But that's not what we're interested in here.

In Python 3.x, you can replace any reference to Ellipsis with that of its token: ... So, with that in mind, the above example could be re-written as:
class QueryThing:
    handle = ...
    
    def __init__(self, db):
        if db and hasattr(db, 'get_handle'):
            self.handle = db.get_handle()

>>> query = QueryThing(some_db)
>>> query.handle
Ellipsis
Here we can see that there's obviously a problem with the db object itself, and no attempt was ever made to write to the .handle propery.

I like the visual "empty slot"-ness the Ellipsis denotes in the class definition. It's a simple pattern, sure, and it isn't meant to replace actual error handling. However, I find it to be a nice way to provide a semantic distinction that an overuse of None doesn't.

No comments:

Post a Comment