Grant Edwards wrote:
Personally, I don't really like the idea that falling off the
botton of a function implicitly returns None. It's just not
explicit enough for me. My preference would be that if the
function didn't execute a "return" statement, then it didn't
return anyting and attempting to use a return value would be an
error.
This is a bad idea. Classically, distinguishing between functions that
return things and functions that don't return things explicitly divides
the "callable object" space. From my CS101 class with its incredibly
exciting dive into the world of useless pseudocode, callables that
returned things were called 'functions' and callables that didn't were
called 'procedures'.
Some languages do make this distinction; QBASIC, for example, had
'gosub' separate from function calls.
What do you do for an early break from a function that still returns
not-even-None [ReallyNone], "return?" That looks and acts like a 'real'
return statement, and the distinction between
return-without-a-value-so-maybe-except and return-with-a-value is
suddenly magnified to real importance.
Further, and I consider this a truly damning case, look at decorater. A
naive "logging" decorator could be defined like this:
def logger(func):
def new_func(*args, **kwargs):
print '%s called with:' % func.__name__, args, kwargs
retval = func(*args,**kwargs)
print '%s returns:', retval
return retval
return new_func
This logger works without modification for both value and non-value
returning functions. Its output isn't quite as pretty for non-value
functions, but it works and the implementation is both simple and flexible.
With a function-schism, to keep its simple implementation 'logger' would
have to be rewritten as 'flogger' (same as current-logger, for use on
functions), and 'plogger' (for use on procedures). The downside here is
that if the function/method changed to or from a procedure, the
decorator would have to be switched.
Alternatively, the logger decorator could be longer and explicitly catch
the possible exception. But why should we have to write like that, for
a use-case that doesn't even represent a true error -- arguably not even
an exceptional case? Python's definitely not a B&D language, talk of
floggers aside.