CSC207 Software Design
Lectures
Object Models

Background

Languages are designed, just like programs

Someone decides what the language is for

Someone decides what features it's going to have

Can't really understand a language until you have seen at least two

Java and Python have more similarities than differences

But the differences help explain why each language is the way it is

Typing

Java uses strong typing

Type of each variable must be declared

Variable X of type T can only refer to instances of that type (or derived types)

Allows method overloading on argument type

Python uses untyped variables and typed values

Eliminates need for type declarations

But makes overloading on argument type impossible

Have to switch on type instead

Which is harder to extend

Primitive vs. Reference Types

Both languages distinguish between primitive types and reference types

Distinction made for performance reasons

Primitive types:

Simple data values (e.g. integer) without methods

Immutable

Cannot be referenced

Reference types:

Dynamically allocated and referenceable

Have methods

There Are Lots of Other Choices

In Smalltalk and Ruby, everything is a first-class object with methods

# A small Ruby example with an anonymous function
5.upto(10) { |i| print i, " " }
5 6 7 8 9 10

In C++, objects can be on the stack, or on the heap

If they're on the stack, they are automatically destroyed when the declaring method returns

Which opens up a ton of security holes

class C {
    public C() {
        x = 0;
    }
    public int x;
}

C * good() {
    return new C();
}

C * bad() {
    C onStack;
    return &onStack;
}

int main(int argc, char * argv[]) {
    C * g = good();
    C * b = bad();
}

[Objects on Stack]

Adding Members to Python Objects

Python "objects" are really dictionaries

Well, sort of

The notation x.y means (something like) x["y"]

Can access this dictionary directly as x.__dict__

Can add new members/methods on the fly

Just as you do in a constructor

Very handy

But can easily yield unmaintainable code

class Pair:
    def __init__(self, left, right):
        self.left = left
        self.right = right

p1 = Pair("a", "b")
print p1.__dict__
{'right': 'b', 'left': 'a'}

p1.middle = "hello"
print p1.middle
hello

print p1.__class__.__dict__
{'__module__': '__main__', '__doc__': None,
 '__init__': <function __init__ at 0x00867FB8>}

Static vs. Dynamic Models

Java's object model is static

Methods are compiled to create blocks of code

Once loaded, code cannot be modified

New code cannot be generated on the fly

Except by writing text, compiling it, and loading result

Python's object model is dynamic

Code is compiled as they are seen

New methods can be loaded on top of old ones

Methods can be added to classes after they have been created

class C:

    def __init__(self):
        self.value = 0

    def method(self, arg):
        self.value += arg

    def __str__(self):
        return `self.value`

obj = C()
obj.method(5)
print obj

def func(self, arg):
    self.value -= arg

C.func = func
obj.func(2)
print obj

5
3

Dynamic Evaluation

Every programming system turns text into instructions, then executes the instructions

In Java and C++, these operations are performed by two separate programs (compiler and runtime)

In Python, they are performed by the same program (the interpreter)

So why not compile, load, and execute code within a running program?

Allows programs to add new code to themselves

This is how import works

Allows users to enter commands on the fly

Opens up a ton of security holes

Using eval in Python

import sys

x = 1
y = 2
z = eval("x + y")
print z
3

line = sys.stdin.readline() # user enters "print x + y + z"
eval(line)
6

Inheritance

Java classes can extend one parent, and implement zero more interfaces

Python has no notion of an "interface"

Methods are looked up at runtime

So X and Y are interchangeable if their methods have the same names and number of arguments

No common ancestors required

Python classes can extend any number of parents

Multiple inheritance

class Divider:
    def __init__(self, val):
        self.div = val
    def doDiv(self, input):
        return input / self.div

class Multiplier:
    def __init__(self, val):
        self.mul = val
    def doMul(self, input):
        return input * self.mul

class Factor(Divider, Multiplier):
    def __init__(self, d, m):
        Divider.__init__(self, d)
        Multiplier.__init__(self, m)

f = Factor(2, 5)
print f.doDiv(4)
print f.doMul(3)

2
15

Collision

Multiple inheritance obviously useful

But how to handle collisions?

Outlaw multiple inheritance

Require users to resolve collisions when declaring derived classes

Specify a search order

Any useful programming language contains a certain amount of grit

You can move it around, but you can't get rid of it

[Multiple Inheritance]

A Universe of Choices

There are many other ways to implement inheritance

E.g. JavaScript has no classes

Add members and methods to one object

Then clone it to create new instances

A prototype-based language

Inheritance implemented by:

Cloning the parent

Adding/changing members and methods

Using the modified child as a new prototype

Generic Programming

C++ supports generic programming using templates

Java 1.5 will too

Don't specify types when defining classes

Instead, use type variables

Then instantiate that class by filling in those placeholders with actual types

Compiler can often do this automatically

Allows programmers to express patterns that cut across type hierarchies

E.g. swap, min, max, etc.

Generic Methods

class Example {

    template<class T>
    public static void swap(T a, T b) {
        T tmp = a;
        a = b;
        b = tmp;
    }

    public static void main(String[] args) {

        String[] x = new String{"X1", "X2"};
        String[] y = new String{"Y3"};
        swap(x, y);

        List left = new ArrayList();
        List right = new LinkedList();
        swap(left, right);
    }
}

Generic Classes

template<class TL, class TR>
class Pair {
    public Pair(TL left, TR right) {
        fLeft  = left;
        fRight = right;
    }

    public TL getLeft() {
        return fLeft;
    }

    ...etc...

    protected TL fLeft;
    protected TR fRight;
}

public static void main(String[] args) {
    Pair<Integer, String> p1 = new Pair(123, "abc");
    Pair<String, Float> p2   = new Pair("xyz", 25.2);
    String s1 = p1.getLeft();   // fails to compile
    String s2 = p2.getLeft();   // works
}

Conclusion

There is no such thing as "the best language"

C++ is faster than Java, but permits errors that Java doesn't

Multiple inheritance allows reuse, but complicates maintenance

But some are better than others

E.g. Python is more readable than Perl

Each one is a vehicle for expressing certain patterns

The patterns are what matters


$Id: objmodel.html,v 1.1.1.1 2004/01/04 05:02:31 reid Exp $