[Python-3000] Use case for generics

Talin talin at acm.org
Sat May 13 23:08:22 CEST 2006


One way of thinking about generic functions is that they are the dynamic 
languages' equivalent to C++ function overloading. Now, there are lots 
of valid (and some not-so-valid) use cases for function overloading; I'm 
just going to pick one of the most common ones.

Many GUI libraries have the concept of a "Rectangle" class which 
represents the area of a widget. Typically, a rectangle can be 
constructed in several ways:

1) From 4 scalars:

     r = Rectangle( x, y, w, h )

2) From two points, representing the top left and lower right corners:

     r = Rectangle( minpos, maxpos )

3) From a position and a size:

     r = Rectangle( position, size )

In order to support this last use case, a special "Size" class is 
defined which is distinct from the "Point" class, and which has "width, 
height" members instead of "x, y" members. (Essentiallly points and 
sizes are both 2D vectors, where points represent absolute locations and 
sizes represent relative locations.)

The following is an implementation, in Python, of a hypothetical 
Rectangle class using generic functions, followed by the same class 
without generics. I've tried my best to make the non-generic version as 
non-obfuscated as possible, so that the comparison would be fair.

(The non-generic version doesn't support keyword args, because I 
couldn't figure out how to do it cleanly; but I'm not sure whether the 
generic version would support keywords or not.)

(And I apologize that my whitespace conventions don't match the 
standard; I work hard to fix that in the PEPs, but its too much effort 
to fix that for this example.)

# Indicates a location in 2D space
class Point( object ):
     __slots__ = ( 'x', 'y' )

     def __init__( self, x, y ):
         self.x = x
         self.y = y

# The size of an item in 2D space
class Size( object ):
     __slots__ = ( 'w', 'h' )

     def __init__( self, w, h ):
         self.w = w
         self.h = h

# A rectanglar area in 2D space
class Rectangle( object ):
     __slots__ = ( 'x', 'y', 'w', 'h' )

     def __init__( self, x=0, y=0, w=0, h=0 ):
         self.x = x
         self.y = y
         self.w = w
         self.h = h

     def __init__( self, position:Point, size:Size ):
         self.x, self.y = position.x, position.y
         self.w, self.h = size.w, size.h

     def __init__( self, ulpos:Point, lrpos:Point ):
         self.x, self.y = ulpos.x, lrpos.y
         self.w = lrpos.x - ulpos.x
         self.h = lrpos.y - ulpos.y

# Same implementation but without generics
class Rectangle( object ):
     __slots__ = ( 'x', 'y', 'w', 'h' )

     def __init__( self, *args ):
         if len( args ) == 2 and isinstance( args[ 0 ], Point ):
             if isinstance( args[ 1 ], Point ):
                 self.from_ul_lr( *args )
             elif isinstance( args[ 1 ], Size ):
                 self.from_pos_size( *args )
             else:
                 raise TypeError
         else:
             self.from_scalars( *args )

     def from_scalars( self, x=0, y=0, w=0, h=0 ):
         self.x = x
         self.y = y
         self.w = w
         self.h = h

     def from_pos_size( self, position:Point, size:Size ):
         self.x, self.y = position.x, position.y
         self.w, self.h = size.w, size.h

     def from_ul_lr( self, ulpos:Point, lrpos:Point ):
         self.x, self.y = ulpos.x, lrpos.y
         self.w = lrpos.x - ulpos.x
         self.h = lrpos.y - ulpos.y


-- Talin



More information about the Python-3000 mailing list