Python Generics, Guards, and Overloading
As I said in my <a
href="http://llimllib.f2o.org/blog/serve/entry/erlang.html">last post</a>,
I've been looking <a href="http://erlang.org">erlang</a> lately, and I'm very
impressed with generic functions, pattern matching, and guards. As I read more
code, I only like them more and more. I'm inclined to agree with 
<a href="http://dirtsimple.org">Phillip</a> that
they
<a href="http://dirtsimple.org/2005/01/like-acid-for-frameworks.html">"capture 
something really fundamental"</a> about programming.<p>
(disclaimer: I am new to this style of programming.
I'm just thinking out loud. People have probably already had this
discussion in more detail.)<p>
As you know if you have been keeping up with Python blogs, 
Phillip has been working hard on adding the aforementioned features to Python by
abusing decorators (hey, he admitted it). Here's what a generic factorial 
function can look like with his <code>dispatch</code> module:<p>
<textarea rows="11" cols="50">@dispatch.generic()
def fact(n):
    """Factorial"""

@fact.when('n == 0')
def ret_one(n):
    return 1

@fact.when('n > 0')
def do_fact(n):
    return n * fact(n-1)</textarea><p>
While it's very cool that it works, I find it hard to imagine a less Pythonic
syntax than this. Defining a new function name for each version of 
<code>fact</code> really hurts
readability, and the guards become more prominent than the
actual function definition. Compare it with the Erlang version, and its
deficiencies become clearer:<p>
<textarea rows="4" cols="50">fact(0) ->
    1;
fact(N) ->
    N * fact(N-1).</textarea><p>
So, if we want generics in Python, what would they ideally look like? Well, that
question interests me, so I'm going to go into pie-in-the-sky mode and throw
this out:<p>
<textarea rows="4" cols="50">def fact(0):
    return 1
def fact(n):
    return n * fact(n-1)</textarea><p>
Isn't that pretty? In my imaginary world,
<code>fact(0)</code> is automatically translated into a guard that only allows 
the first function to be called when <code>n</code> is 0. What are guards, and 
what do they look like in Bill-Mill-land?
Some code should make it clear:<p>
<textarea rows="4" cols="50">def move_pointer(x, y) when x > 0 and y > 0:
    #move the pointer
def move_pointer(x, y):
    raise CoordsError, "Negative coord"</textarea><p>
I don't think I even need to explain that code; if x and y are positive, the 
first function is called. Else, the second one is called. It <b>just makes sense</b>.
If you guessed that the function <code>fact(0)</code> above would expand to
<code>fact(n) when n == 0:</code> , then you're following along. More
generally, any constant in the parameter list could be expanded by the
interpreter into a guard.<p>
This next example demonstrates both overloading, and the use of guards for
dynamic type checking. Imagine that this follows immediately after the previous
code sample:<p>
<textarea rows="6" cols="50">def move_pointer((x, y)) when adapt(y, int):
    #call looks like: move_pointer(point)
def move_pointer(*args):
    #handle default match; Python should raise
    #an error if no function match is found
    #and no default match is provided</textarea><p>
The first function accepts one argument, a 2-tuple, and unpacks it 
to the variables <code>x</code> and <code>y</code>. If <code>y</code>
can be adapted to an <code>int</code>, then the function is called. If none
of the more specific <code>move_pointer</code> functions can be found, then 
the default, <code>move_pointer(*args)</code> would be called. If no default
were found, an exception would be raised.<p>
Basically, what I'm dreaming of in this post is stealing some elegant
syntax for Phillip's work from Erlang and porting it to Python. I think 
that generics, guards, and overloading are a better addition to Python
than is static typing, bringing some of the benefits that have been proposed
for static typing, without the drawbacks.<p>
UPDATE: Added return statements to the first "imaginary Python" code sample. I
never meant to leave them off. Thanks to <a 
href="http://www.drbeat.li/">Beat Bolli</a> for pointing this out.
<!--keywords: erlang, python, generic_functions, language, syntax, design, computer, programming-->
<!--time: 01-13-05 23:42-->
