[Edu-sig] An intro without objects??

Kirby Urner pdx4d@teleport.com
Mon, 28 May 2001 10:28:05 -0700


In the chapter entitled 'Building Abstractions with Data' in
'Structure and Interpretation of Computer Programs', the
rational number object is introduced (Sec. 2.1.1.)...

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-13.html

... except not as "objects", but in terms of procedures and
data, with the data structure in question being the "pair"
i.e. a (numerator, denominator) tuple, with relevant procedures
for forming such pairs (cons) and extracting either (car, cdr).

What you're left with is a sense of data on the one hand, 
and procedures for operating on that data on the other.  I
miss the higher level abstraction of "object", in which the
relevant procedures are encapsulated, along with the data 
structure, such that our interface to the "rational number
object" contains whatever functionality we like.  Plus I miss
the ability to easily override primitive operators, such 
that I can multiply, add, subtract rational numbers (a.k.a.
fractions) using *, + - etc.  This is an important abstraction
in math -- to realize that these operators may be redefined 
at will (yet usually according to various rules of group 
theory, e.g. whatever * means, there should be an identity
object ident such that anyobj * ident = anyobj = ident * anyobj).

In the Python approach, we might begin in the "wishful thinking" 
stage by sketching out a shell object:

     class Rat:

        def __init__(self,p,q):
            self.numer = p
            self.denom = q

        def __add__(self,other):
            pass

        def __sub__(self,other):
            pass

        def __mul__(self,other):
            pass

  >>> a = Rat(2,3)
  >>> a.numer
  2
  >>> a.denom
  3

and so on.  We'll also want to have a way of representing 
rational numbers to the screen, along the lines of:

       (define (print-rat x)
           (newline)
           (display (numer x))
           (display "/")
           (display (denom x)))

i.e.

        def __repr__(self):
           return "%s/%s" % (self.numer,self.denom)

  >>> a = Rat(2,3)
  >>> a
  2/3

And so on.

I prefer this approach, because we're setting up a class definition,
not a sandbox of procedures and data, with the procedures tied to the
data simply by the programmer's knowledge and/or by documentation.  
The class definition is itself a kind of data structure, in that it 
files the relevant methods with the data, under the same heading.  
No one has to keep track of what procedures "belong" with what data.
That's built in to the class definition.

Furthermore, we're setting up an inheritable framework.  A subclass 
could pick up where Rat leaves off, and further elaborate methods
-- perhaps it would simply have a different representation scheme,
outputting "mixed" fractions e.g. 5 1/4 instead of 25/4.  This is 
commonly done with a global variable switch, but a subclass would
work.  In the case of Matrices, any ol' Matrix object would by nxm,
with a subclass, Sqmatrix, being for nxn or square matrices -- where
only these latter have certain methods, such as determinant and 
inverse.

I guess I'm feeling uneasy with a foundational approach that 
doesn't bring in the concept of objects closer to the beginning.  
The object concept is an important one.  Just procedures and data, 
without objects, seems a rather scattered/cluttered approach.  
Shouldn't newcomers learn the object model right about where this 
rational numbers example is presented?  Certainly building rational
numbers as objects would be a standard exercise in a Python-focused 
curriculum (might be a math class -- if the distinction matters).

Kirby