Class Notes
(807,075)

United States
(312,354)

Computer Science
(355)

COMPSCI 61A
(130)

De Nero
(43)

Lecture

# CS61A Lecture 21: Generic Functions

Unlock Document

University of California - Berkeley

Computer Science

COMPSCI 61A

De Nero

Fall

Description

Generic Functions of Multiple Arguments
A function might want to operate on multiple data types
Last time:
Polymorphic functions using message passing
Interfaces: collections of messages that have specific behavior conditions
Two interchangeable implementations of complex numbers
Today:
An arithmetic system over related types
Type dispatching
Data-directed programming
Type coercion
What’s different?
Today’s generic functions apply to multiple arguments that don’t share
common interface
Representing Numbers
Rational numbers represented as a numerator and denominator
class Rational:
"""A rational number represented as a numerator and denominator.
All rational numbers are represented in lowest terms.
>>> Rational(6, 4)
Rational(3, 2)
>>> add_rational(Rational(3, 14), Rational(2, 7))
Rational(1, 2)
>>> mul_rational(Rational(7, 10), Rational(2, 7))
Rational(1, 5)
"""
def __init__(self, numer, denom):
g = gcd(numer, denom)
self.numer = numer // g
self.denom = denom // g
def __repr__(self):
return 'Rational({0}, {1})'.format(self.numer, self.denom)
def __str__(self):
return '{0}/{1}'.format(self.numer, self.denom)
def __add__(self, other):
return add_rational(self, other)
def __mul__(self, other):
return mul_rational(self, other) Complex Numbers: the Rectangular Representation
Special Methods for Arithmetic
Adding instance sod user-defined classes with __add__.
def __add__ (self, other):
return add_rational(self, other)
We can also __add__ complex numbers, even with multiple representations
Also __mul__ complex numbers
Can use normal operators + and * instead of writing mul_complex or add_complex
Composition better
Can also use dot expression
Type Dispatching
Data abstraction and class definitions keep types separate
Some operations need cross type boundaries
Define a different function for each possible combination of types for which an
operation (e.g. addition) is valid
def complex(z):
return type(z) in (ComplexRI, ComplexMA)
def rational(z):
return type(z) is Rational
def add_complex_and_rational(z, r):
return ComplexRI(z.real + r.numer/r.denom, z.imag)
def add_dispatching(z1, z2):
"""Add z1 and z2, which may be complex or rational. >>> add_dispatching(ComplexRI(1.5, 0), Rational(3, 2))
ComplexRI(3.0, 0)
>>> add_dispatching(Rational(5, 3), Rational(1, 2))
Rational(13, 6)
"""
if complex(z1) and complex(z2):
return add_complex(z1, z2)
elif complex(z1) and rational(z2):
return add_complex_and_rational(z1, z2)
elif rational(z1) and complex(z2):
return add_complex_and_rational(z2, z1)
else:
return add_rational(z1, z2)
Tag-Based Type-dispatching
Idea: Use a dictionary to dispatch on pairs of types
def type_tag(x):
"""Return the tag associated with the type of x."""
return type_tags[type(x)]
type_tags = {ComplexRI: 'com', ComplexMA: 'com', Rational: 'rat'}
def add(z1, z2):
"""Add z1 and z2, which may be complex or rational.
>>> add(ComplexRI(1.5, 0), Rational(3, 2))
ComplexRI(3.0, 0)
>>> add(Rational(5, 3), Rational(1, 2))
Rational(13, 6)
"""

More
Less
Related notes for COMPSCI 61A