H. Conrad Cunningham
28 August 2018
Copyright (C) 2018, H. Conrad Cunningham
Acknowledgements: I created these slides in Fall to accompany Chapter 3, Object-Based Paradigms, of the book Exploring Languages with Interpreters and Functional Programming.
Browser Advisory: The HTML version of this document may require use of a browser that supports the display of MathML. A good choice as of August 2018 is a recent version of Firefox from Mozilla.
Examine general object model for object-oriented programming paradigm
Examine related paradigms: object-based, class-based, and prototype-based
Key idea: Real world can be accurately described as collection of interacting objects
1 | simplifies development |
2 & 3 | enable reuse, prototyping, incremental development |
4 | supports design for change |
Uses same basic entities (objects) throughout software development lifecycle
Identifies basic objects during analysis
Identifies lower-level objects during design, reusing existing object descriptions where appropriate
Implements objects as software structures (classes)
Maintains object behaviors
Objects (abstract data structures)
Classes (abstract data types)
Inheritance (hierarchical relationships among abstract data types)
Subtype polymorphism
Dynamic binding? Consider implementation technique for polymorphism rather than characteristic
Essential characteristics
[a] state
[b] operations
[c] identity
Important but non-essential characteristics
[d] encapsulation
[e] independent lifecycle
Objects usually first-class entities
store in data structures
pass to / return from procedures and functions
Collection of information held by object:
can change over time
can change only as result of operation on object
cannot change spontaneously
Attributes – components of state
Operation – procedure takes object state & arguments, changes state or returns values
Object permits certain operations, not others
Mutable object – operation can change stored state in-place – imperative language
Immutable object – operation cannot change stored state in-place, returns modified object with new state
Can distinguish between two distinct objects
even with same state and operations
perhaps in different physical locations (e.g. memory address)
Encapsulation – private features not directly accessible outside
E.g. Java private
instance
variables and method encapsulated
Object-based languages without true encapsulation
Python – uses obfuscation, programming conventions
Lua – uses programming conventions, advanced programming techniques
Oberon – uses modules for encapsulation, extended record types for other OO features
Object exists independently from program unit that created it (independent lifetime)
Usually means dynamic allocation on heap
But some languages allow object on stack – e.g., C++
Each StudentDesk
distinct
from others – unique identity
State – location, orientation, person using, items in basket, items on top
State-changing operations – mutator, setter, command
“move desk”, “seat student”, “remove from basket”
State-observing operations (accessor, getter, observer, query)
“is occupied”, “report items on desktop”
Language object-based if supports objects as feature
Ada, Modula, Clu, C++, Java, Scala, C#, Smalltalk, and Python 3
Pascal (without module extensions), Algol, Fortran, C
Class – template or factory for creating objects
describes collection of related objects – instances
common operations and possible states for instances
closely related to concept of type
Class description includes definitions of:
operations
set of possible states
Class StudentDesk
appropriate data attributes and operations
template for instances
Other classes
Class-based language
object-based language with “class” as feature
every object has class
Clu, C++, Java, Scala, C#, Smalltalk, Ruby, Ada 95:
Ada 83, Modula, Lua, core JavaScript,
Some statically typed languages treat classes as (nominal) types: Java, Scala, C++, C#
Some dynamically types languages treat types as what operations supported (duck typing): Smalltalk, Ruby
Python 3? both nominal typing and duck typing
Types chapter has more detail
Goal: Encourage reuse of design and code
Class C inherits from class P if C’s objects form a subset of P’s objects.
Class C supports all class P operations/state
Class C may support more operations/state
Class C subclass, child, derived class
Class P superclass, parent, base class
Class P generalization of class C; C specialization of P
// Java or Scala
class Furniture // extends cosmic root class for references
{ ... } // (java.lang.Object, scala.AnyRef)
class Desk extends Furniture
{ ... } // implement "move" op
class StudentDesk extends Desk
{ ... } // share "move" from Desk
class ComputerDesk extends Desk
{ ... } // share "move" from Desk
Problems with multiple inheritance in StudentDesk
What if “move” in both Desk
and Chair
What if data fields in Furniture
– 1 copy or
2?
Solutions complex:
Java and Scala – do not allow – use interfaces
Other languages allow (including C++ and Python 3) but have complex rules
// Java
interface Location3D
{ ... } // variable defs, method signatures
interface HumanHolder
{ ... }
interface Seat extends Location3D, HumanHolder
{ ... } // default method defs in newer Java
interface BookHolder
{ ... }
interface BookBasket extends Location3D, BookHolder
{ ... }
class StudentDesk extends Desk implements Seat, BookBasket
{ ... }
also called polymorphism by inheritance, inclusion polymorphism, subtyping
Usually at runtime – dynamic binding to nearest implementation
Inherits from cosmic root class object
by
default – otherwise parents in parenthesis after class name
Uses initializer __init__
, not
really constructor
Lists receiver object as first parameter – convention self
Has instance variables count
, maxc
; access with self.
def has_more(self,c,m): # (5)
return c <= m
def adv(self): # (6)
self.count = self.count + 1
def counter(self): # (7)
while self.has_more(self.count,self.maxc):
print(f'{self.count}') # (8)
self.adv()
Boolean function has_more()
– hook method in
Template Method design pattern
Procedure adv()
sets self.count
–
hook method
def counter(self): # (7)
while self.has_more(self.count,self.maxc):
print(f'{self.count}') # (8)
self.adv()
Procedure counter()
–
primary public interface to object – template method in
Template Method design pattern
Expression f'{self.count}'
– Python 3.7 interpolated string
Prototype-based language
Has objects but no classes
Copies (clones) existing object (prototype) to create new
Prototype:
Object with collection of slots
Each slot data attribute or operation.
Class-based language have crisp boundaries – in class or not
Prototype-based language have fuzzy boundaries when needed
Categories blend into each other
Cloning approach more flexible
Using classes
Have Student
class
Want some Student
to be chess player
Create new class ChessPlayingStudent
But inherit from Student
or
ChessPlayer
?
Or compose Student
and ChessPlayer
(have as fields of ChessPlayingStudent
)
Using prototype objects
Have Student
object
Want some Student
to be chess player
Clone existing object, dynamically add new data attributes and
operations – get ChessPlayingStudent
object
Consider Student
named Tony
Graduates with BSCS becomes Alumnus
But hires in IT, also becomes Staff
Joins graduate CS program, so still Student
Teaches course, also becomes Faculty
Learns to play chess
Can evolve object Tony
object using prototype
cloning
May delegate to prototype object rather then copy it completely
Put new or changed attributes in new object slots
Delegate unchanged data attribues and operations to prototype
Prototype and delegation
more basic than classes and inheritance
can simulate classes and inheritance
Self
NewtonScript, JavaScript, Lua, Io
Python (with package prototype.py)
Dynamically typed, multiparadigm language with design principles:
Can only use standard C language and library
Must be efficient in use of memory and processor time
Must support interoperability with C programs in both directions
Why?
C ubiquitous across hardware/OS platforms
Gives portability, embeddability, efficiency
Extending apps with user-written Lua scripts
In game scripting, Wikipedia templates, Pandoc filters, etc.
Provide meta-mechanisms for implementing features instead of lots of features
Makes Lua simple but powerful
Examples:
No classes or inheritance, but mechanism to build them
Table only data structure, but flexible and efficient
Metatables and metamethods
First class functions (closures)
State (i.e. values associated with keys)
Operations by associating function closures with keys
Closure is function def plus free variable values
Identity independent of state
Lifecycle independent of the code that created it
No direct encapsulation, rely on convention and advanced techniques
Reference to function closure in table obj
(expression) at key method
Represented by syntactic sugar
Receiver obj
called parameter
self
in body
Metatable mechanism with metamethod __index
:
delegates missing key access to different table
enables prototype-based paradigm
-- File CountingPB.lua
local CountingPB = {count = 1, maxc = 0} -- (1)
function CountingPB:new(mixin) -- (2)
mixin = mixin or {} -- (5)
local obj = { __index = self } -- (4)
for k, v in pairs(mixin) do -- (5)
if k ~= "__index" then
obj[k] = v
end
end
return setmetatable(obj,obj) -- (6,7)
end
function CountingPB:has_more(c,m) -- (2)
return c <= m
end
function CountingPB:adv() -- (2)
self.count = self.count + 1
end
function CountingPB:counter() -- (2)
while self:has_more(self.count,self.maxc) do
print(self.count)
self:adv()
end
end
return CountingPB -- (3)
-- File CountingPB.lua
local CountingPB = {count = 1, maxc = 0} -- (1)
...
function CountingPB:new(mixin) -- (2)
...
function CountingPB:has_more(c,m) -- (2)
...
function CountingPB:adv() -- (2)
...
function CountingPB:counter() -- (2)
...
return CountingPB -- (3)
Create module CountingPB
as
table with default values (prototype obj)
Define methods new()
, has_more
, etc
Return CountingPB
from require
call
function CountingPB:new(mixin) -- (2)
mixin = mixin or {} -- (5)
local obj = { __index = self } -- (4)
for k, v in pairs(mixin) do -- (5)
if k ~= "__index" then
obj[k] = v
end
end
return setmetatable(obj,obj) -- (6,7)
end
Method new
(arbitrary name)
constructs clones
Creates as table with __index
set to
receiver
Copies mixin
entries into
clone, adds or changes
Sets clone’s metatable to clone itself
Returns clone object – module convention
On access to undefined key
If no metatable set, return nil
If metatable set, check __index
entry
nil
Prototype delegation functionality
-- File CountingPB.lua
local CountingPB = {count = 1, maxc = 0} -- (1)
function CountingPB:new(mixin) -- (2)
mixin = mixin or {} -- (5)
local obj = { __index = self } -- (4)
for k, v in pairs(mixin) do -- (5)
if k ~= "__index" then
obj[k] = v
end
end
return setmetatable(obj,obj) -- (6,7)
end
function CountingPB:has_more(c,m) -- (2)
return c <= m
end
function CountingPB:adv() -- (2)
self.count = self.count + 1
end
function CountingPB:counter() -- (2)
while self:has_more(self.count,self.maxc) do
print(self.count)
self:adv()
end
end
return CountingPB -- (3)
Load CountngPB.lua
module, create object, call counter
Gives output
0
1
2
...
10
Create clone of object x
Give output
10
11
12
13
14
15
z = y:new( { maxc = 400,
has_more = function (self,c,m)
return c ~= 0 and math.abs(c) <= math.abs(m)
end,
adv = function(self)
self.count = self.count * 2
end,
bye = function(self) print(self.msg) end
msg = "Good-Bye!" } )
z:counter()
z:bye()
Gives output
16
32
64
128
256
Good-Bye!
OO paradigm usually enforces particular policy for object creation and inheritance
Programming outside policy difficult
PB paradigm provides low-level mechanisms – allows programmers to define own policies flexibility in code
Can give incompatible structures from one program to another
Defined object characteristics
Essential: state, operations, identity
Important: encapsulation; independent lifecycle
Defined general object model for OO paradigm – objects, classes, inheritance, subtype polymorphism
Examined Python 3 OO class example
Defined object-based, class-based, and prototype-based paradigms
Python 3 example: CountingOO.py
Similar OO Scala example: CountingOO.scala
Lua example: CountingPB.lua
Example use CountingPB_Test.lua