Adding static typing to Python

Quinn Dunkan quinn at regurgitate.ugcs.caltech.edu
Thu Feb 21 19:15:48 EST 2002


On Wed, 20 Feb 2002 17:12:36 +0000 (UTC), gbreed at cix.compulink.co.uk
<gbreed at cix.compulink.co.uk> wrote:
>Alexander Jerusalem wrote:
>
>> I just looked up what CLOS does. I don't know if you call that static
>> typing or not.

You wouldn't.  At least we should agree that lisp is dynamically typed :)

>> typing or not. In any case, CLOS does have type declarations in the
>> source code which is what I want and what enables the features I'd
>> like to see in Python. For example in CLOS you can have the following
>> method declarations:
>> 
>>  (defmethod Area ((C Circle)) (* pi (Square (Radius C)))
>>            (defmethod Area ((R Rectangle)) (* (Width R) (Height R)))
>>            (defmethod Area ((Sq Square)) (Square (Width Sq)))
>>            OR (defmethod Height ((Sq Square)) (Width Sq))
>
>But you can do that in Python:
>
>>>> def area(shape):
>...   if isinstance(shape, Circle):
>...     return math.pi*shape.radius**2
>...   if isinstance(shape, Rectangle):
>...     return shape.width*shape.height
>...   if isinstance(shape, Square):
>...     return shape.width**2
>...   raise TypeError, "unknown shape"
>...

This kind of giant typecase is exactly the sort of thing that OO is supposed
replace.

>It can't take much imagination to see how it could be sugared to work with 
>multiple functions with types resolved at run time.

Right:
def area(Shape(o)):
    ...
def area(Rectangle(o)):
    ...
def area(Circle(o)):
    ...

But this is no longer python.

>                                                     As for strict, 
>strong, static, explicit typing (which may be a straw man) it looks *less* 
>suitable for this example.

Yeah, I agree that static typing is orthogonal to OO-style function dispatch.

>Say you want to include a triangle in your list of shapes.  So, you add
>
>...   if isinstance(shape, Triangle):
>...     return shape.base*shape.height
>
>to the area function.

No, you shouldn't have to modify area(), but add a shape() method to Triangle.

>                       But then, will all the other functions that call 
>area be allowed to accept a triangle?

Sure.  They specify that they want an object with an area method, and
as soon as you add one of those to Triangle, Triangles becomes acceptable.
This is how static CLOS-esque systems work, like haskell or clean.

>You could make them all subclasses of Shape.  In which case, you have 
>functions defined to use a polymorphic object that depend on function 
>overloading by the real type.  Not all statically typed languages will 
>allow that.

C++ requires special keywords for it, but all statically typed OO languages I
know of do dynamic dispatch.  I certainly don't know every static language out
there, but just because there's a limited implementation somewhere doesn't
mean the concept is unworkable :)

>             If they do, you have the problem that you might have added 
>triangles for some other reason, and forgotten to cater for them in 
>area().  You aren't getting static type checking at all.

Sure you are.  area will reject objects that don't have the proper methods
defined for them.  How it works in haskell is that each class has a minimum
interface that you must implement.  If you don't implement all the methods
of the Shape class, Shape-accepting functions won't accept your objects.
This is less flexible than having to implement *only* the methods the
function actually uses, as in python, but c++ templates are sorta like that.

>Wouldn't it be better to make area a method of the shapes?  And for static 
>typing, make it abstract in the Shape class?

In your above example, that's what it is.  You're just spelling 'circle.area()'
as 'area(circle)'.

I actually like the second better, because lets you do things like
'map(area, shapes)' instead of 'map(lambda o: o.area(), shapes)', as well
as multi-dispatch, and eliminates the 'len(o)' vs 'o.len()' thing.  It also
has other benefits like letting you define a method anywhere you want which
obeys the usual scoping rules (so you can add a 'frobbify' method to the
string class, but not have to worry about it making a global change for
everyone in all modules).

I'm not even sure why the smalltalk style 'object followed by method' notation
caught on, especially since 'function followed by args' has always been
firmly entrenched.



More information about the Python-list mailing list