Functional OOP,
Clojure Style
Yoav Rubin
About me
• Software engineer at IBM Research - Haifa
– Development of development environments
– Large scale products
to small scale research
projects
• Lecture the course “Functional
programming on the JVM” in Haifa
University
{:name Yoav Rubin,
:email yoavrubin@gmail.com,
:blog http://yoavrubin.blogspot.com,
:twitter @yoavrubin}
First thing first
Alan Kay
Alan Kay Edsger W. Dijkstra
Alan Kay Edsger W. Dijkstra
“Perspective is worth 80 IQ points”
Alan Kay
• OOP
• Clojure
Agenda
in
What’s in a software
• Data types that describe the elements of
the domain (nouns)
• State changing operations (verbs)
Type  functionality f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X X
The software matrix
Type  functionality f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X X
The software matrix
Data types, nouns
Type  functionality f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X X
The software matrix
API, verbs,
interfaces
Type  functionality f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X X
The software matrix
implementations of
operationx by Typey
Data directed programming
The expression problem
Philip Wadler
SICP
Deciding which function to use based
on given data
How to add rows and columns to the
matrix without recompiling while
preserving static typing
Let’s talk OOP
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in class
Z means that X is-a Z
Let’s talk OOP
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in class
Z means that X is-a Z
Abstraction
Let’s talk OOP
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in class
Z means that X is-a Z
Let’s talk OOP
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in class
Z means that X is-a Z
Information hiding
Let’s talk OOP
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in class
Z means that X is-a Z
Let’s talk OOP
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in class
Z means that X is-a Z
Polymorphism
Let’s talk OOP
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in class
Z means that X is-a Z
Let’s talk OOP
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in class
Z means that X is-a Z
Inheritance
Type 
functionality
f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X
Inheritance
Type 
functionality
f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X
Inheritance
T4 can say that it is a
T3
Type 
functionality
f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X
Inheritance
T4 can say that it is a
T3
and its implementation
of f3 is found at T3
X
OOP on the matrix
• The rows are the classes
– The domain abstractions we define and use
– Which can hide within them their internal state
• The column headers are interfaces
– Which allow polymorphic usage
• Marked cell in row X and column Y signifies that
class X implements interface Y
– Saying that the implementation itself resides in Class
Z means that X is-a Z
How is it all related to Clojure?
What is Clojure
What is Clojure
• A Lisp
• A functional language
• Dynamically typed
• Emphasis on immutability
• Treats concurrency as an elementary part of life
– Not as a burden
• Compiles to bytecode
– Of the JVM / CLR / JS (as the web’s bytecode)
• Excellent “great ideas to WTF” ratio
General structure
• A Clojure project is built of namespaces
• In each namespace there are functions
and data elements
• Functions can be either public or private
– Either visible or not visible outside of the
namespace
General structure
• A Clojure project is built of namespaces
• In each namespace there are functions
and data elements
• Functions can be either public or private
– Either visible or not visible outside of the
namespace
Functional Information hiding
How to define rows in Clojure?
Creating new types
• Metaobjects – a mechanism that allows
description and creation of new datatypes
• We can create our own metaobjects
– E.g., a map that one of its key is “type”
• In Clojure there are two metaobjects
– Type
– Record
The Type metaobject
• Upon definition we need to provide:
– Name
– Member fields
– APIs to implement and their implementation
• Override methods from Object, interfaces,
protocols (soon)
• Cannot introduce new APIs to the matrix
• Can be made mutable
The type metaobject
Definition:
Instantiation:
Usage:
The type metaobject
Definition:
Instantiation:
Usage:
The type metaobject
Definition:
Instantiation:
Usage:
The type metaobject
Definition:
Instantiation:
Usage:
Two main use cases
• You really know what you are doing
• You’re doing it wrong
The Record metaobject
• Similar to the Type metaobject
• Provides a map like behavior
• No mutability
So far in the software matrix
• Added new rows
– New types / records
– No new APIs
• Associate with an existing column
So far in the software matrix
• Added new rows
– New types / records
– No new APIs
• Associate with an existing column
Functional Abstraction
So far in the software matrix
• Added new rows
– New types / records
– No new APIs
• Associate with an existing column
Functional Abstraction
Polymorphism
How to define columns in Clojure?
Adding new APIs
• New APIs for one type
– just add a new function
• Problem: how to handle more types?
• Naïve solution: a simple dispatcher
Now there’s a new tree in town
What can a developer do?
• Re-write the existing tree-map function
– Because editing legacy code is fun…
• Create another tree-map in another namespace
and qualify its calls
– Name collisions
• Create tree-map2
– Complicating both developer’s and user’s code
A deeper look
Type  functionality f1 f2 f3 tree-map
GeneralTree X X X
YetAnotherType X
BinaryTree X X
A deeper look
Type  functionality f1 f2 f3 tree-map
GeneralTree X X X
YetAnotherType X
BinaryTree X X
New column header (API)
A deeper look
Type  functionality f1 f2 f3 tree-map
GeneralTree X X X
YetAnotherType X
BinaryTree X X
New column header (API)
Two
implementations
A deeper look
Type  functionality f1 f2 f3 tree-map
GeneralTree X X X
YetAnotherType X
BinaryTree X X
New column header (API)
Two
implementations
QuadTree
A deeper look
Type  functionality f1 f2 f3 tree-map
GeneralTree X X X
YetAnotherType X
BinaryTree X X
New column header (API)
Two
implementations
QuadTree ?
A deeper look
Type  functionality f1 f2 f3 tree-map
GeneralTree X X X
YetAnotherType X
BinaryTree X X
New column header (API)
Two
implementations
QuadTree ?
Tree-map did too much!!!
In the software matrix:
Need to decomplect the creation of
columns headers from cell marking
Or in software design language:
We need to separate the definition of an
API from its implementation
Creating abstract APIs
• No concrete implementation
• Define a semantic unit
– A set of behaviors that compose an API
• In another place define the mapping
between data types and the API
– Marking of a cell in the matrix
Protocol
• A set of several function signatures
– Just the signature, without implementation
– Dispatch is done based on the run-time type
Protocol
• A set of several function signatures
– Just the signature, without implementation
– Dispatch is done based on the run-time type
The protocol name
Protocol
• A set of several function signatures
– Just the signature, without implementation
– Dispatch is done based on the run-time type
The protocol name
A function signature
(there can be several of these)
Protocols and types
• The linking of a protocol to a type can be
done not as part of the definition of the
type
• This results in the possibility to extend
existing, compiled types
– Extend String
– Extend even nil
Added to an existing type a
new API
Without changing the type
Added to an existing type a
new API
Without changing the type
Functional polymorphism
Still, there are limitations
Protocols allow type based dispatch only
Multi methods
• Polymorphism which is based on a user
defined dispatching function
• The result of the execution of the dispatch
function determines which implementation
will be executes
(dispatch-fn)
take-care-of
::moon
::sun
(tco-sun)
(tco-moon)
dispatcher
(dispatch-fn)
take-care-of
::moon
::sun
(tco-sun)
(tco-moon)
This is the exposed API
dispatcher
(dispatch-fn)
take-care-of
::moon
::sun
(tco-sun)
(tco-moon)
dispatcher
(dispatch-fn)
take-care-of
::moon
::sun
(tco-sun)
(tco-moon)
dispatcher
(dispatch-fn)
take-care-of
::moon
::sun
(tco-sun)
::lightning
(tco-lightning)
(tco-moon)
dispatcher
The multi method name
The dispatching function
Meanwhile, at other namespaces
Meanwhile, at other namespaces
Meanwhile, at other namespaces
Multi method
• We can use the same API for different
data elements
• All we need to know is that they obey that
API
• We can introduce new APIs for existing
types
Multi method
• We can use the same API for different
data elements
• All we need to know is that they obey that
API
• We can introduce new APIs for existing
types
Functional polymorphism
Is-a relationship
• We can define that A is-a B
• The dispatcher would handle A the same
way that it handles B
• (derive ::A ::B)
– if the dispatch function return ::A
– if no value is found for ::A in the dispatcher
– Handle it as ::B
Is-a relationship
Is-a relationship
Is-a relationship
Is-a relationship
Is-a relationship
Is-a relationship
Why did it work
• Derive harms the referential transparency of the multi
method
– The return value may differ if (derive…) was called
– Referential transparency is our friend
• Derive works only with namespace bound keywords
– Those that start with ::
• Clojure localizes the effect of mutability to the
namespace
Type 
functionality
f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X X
T4 isa T2 (for f2)
T4 isa T3 (for f3)
Type 
functionality
f1 f2 f3 f4
T1 X X
T2 X
T3 X
T4 X X X X
T4 isa T2 (for f2)
T4 isa T3 (for f3)
Functional inheritance
Summary
• We’ve seen
– Functional abstraction
– Functional information hiding
– Functional polymorphism
– Functional inheritance
Summary
• We’ve seen functional
– Abstraction
– Information hiding
– Polymorphism
– Inheritance
Summary
• We’ve seen functional OOP
Summary
• We’ve seen functional OOP
Clojure Style
Thank
You!

Functional OOP, Clojure style

  • 2.
  • 3.
    About me • Softwareengineer at IBM Research - Haifa – Development of development environments – Large scale products to small scale research projects • Lecture the course “Functional programming on the JVM” in Haifa University {:name Yoav Rubin, :email [email protected], :blog http://yoavrubin.blogspot.com, :twitter @yoavrubin}
  • 4.
  • 5.
  • 6.
    Alan Kay EdsgerW. Dijkstra
  • 7.
    Alan Kay EdsgerW. Dijkstra
  • 8.
    “Perspective is worth80 IQ points” Alan Kay
  • 9.
  • 10.
    What’s in asoftware • Data types that describe the elements of the domain (nouns) • State changing operations (verbs)
  • 11.
    Type functionalityf1 f2 f3 f4 T1 X X T2 X T3 X T4 X X X X The software matrix
  • 12.
    Type functionalityf1 f2 f3 f4 T1 X X T2 X T3 X T4 X X X X The software matrix Data types, nouns
  • 13.
    Type functionalityf1 f2 f3 f4 T1 X X T2 X T3 X T4 X X X X The software matrix API, verbs, interfaces
  • 14.
    Type functionalityf1 f2 f3 f4 T1 X X T2 X T3 X T4 X X X X The software matrix implementations of operationx by Typey
  • 15.
    Data directed programming Theexpression problem Philip Wadler SICP Deciding which function to use based on given data How to add rows and columns to the matrix without recompiling while preserving static typing
  • 16.
    Let’s talk OOP •The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in class Z means that X is-a Z
  • 17.
    Let’s talk OOP •The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in class Z means that X is-a Z Abstraction
  • 18.
    Let’s talk OOP •The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in class Z means that X is-a Z
  • 19.
    Let’s talk OOP •The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in class Z means that X is-a Z Information hiding
  • 20.
    Let’s talk OOP •The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in class Z means that X is-a Z
  • 21.
    Let’s talk OOP •The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in class Z means that X is-a Z Polymorphism
  • 22.
    Let’s talk OOP •The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in class Z means that X is-a Z
  • 23.
    Let’s talk OOP •The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in class Z means that X is-a Z Inheritance
  • 24.
    Type functionality f1 f2f3 f4 T1 X X T2 X T3 X T4 X X X Inheritance
  • 25.
    Type functionality f1 f2f3 f4 T1 X X T2 X T3 X T4 X X X Inheritance T4 can say that it is a T3
  • 26.
    Type functionality f1 f2f3 f4 T1 X X T2 X T3 X T4 X X X Inheritance T4 can say that it is a T3 and its implementation of f3 is found at T3 X
  • 27.
    OOP on thematrix • The rows are the classes – The domain abstractions we define and use – Which can hide within them their internal state • The column headers are interfaces – Which allow polymorphic usage • Marked cell in row X and column Y signifies that class X implements interface Y – Saying that the implementation itself resides in Class Z means that X is-a Z
  • 28.
    How is itall related to Clojure?
  • 29.
  • 30.
    What is Clojure •A Lisp • A functional language • Dynamically typed • Emphasis on immutability • Treats concurrency as an elementary part of life – Not as a burden • Compiles to bytecode – Of the JVM / CLR / JS (as the web’s bytecode) • Excellent “great ideas to WTF” ratio
  • 31.
    General structure • AClojure project is built of namespaces • In each namespace there are functions and data elements • Functions can be either public or private – Either visible or not visible outside of the namespace
  • 32.
    General structure • AClojure project is built of namespaces • In each namespace there are functions and data elements • Functions can be either public or private – Either visible or not visible outside of the namespace Functional Information hiding
  • 33.
    How to definerows in Clojure?
  • 34.
    Creating new types •Metaobjects – a mechanism that allows description and creation of new datatypes • We can create our own metaobjects – E.g., a map that one of its key is “type” • In Clojure there are two metaobjects – Type – Record
  • 35.
    The Type metaobject •Upon definition we need to provide: – Name – Member fields – APIs to implement and their implementation • Override methods from Object, interfaces, protocols (soon) • Cannot introduce new APIs to the matrix • Can be made mutable
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
    Two main usecases • You really know what you are doing • You’re doing it wrong
  • 41.
    The Record metaobject •Similar to the Type metaobject • Provides a map like behavior • No mutability
  • 42.
    So far inthe software matrix • Added new rows – New types / records – No new APIs • Associate with an existing column
  • 43.
    So far inthe software matrix • Added new rows – New types / records – No new APIs • Associate with an existing column Functional Abstraction
  • 44.
    So far inthe software matrix • Added new rows – New types / records – No new APIs • Associate with an existing column Functional Abstraction Polymorphism
  • 45.
    How to definecolumns in Clojure?
  • 46.
    Adding new APIs •New APIs for one type – just add a new function • Problem: how to handle more types? • Naïve solution: a simple dispatcher
  • 49.
    Now there’s anew tree in town
  • 50.
    What can adeveloper do? • Re-write the existing tree-map function – Because editing legacy code is fun… • Create another tree-map in another namespace and qualify its calls – Name collisions • Create tree-map2 – Complicating both developer’s and user’s code
  • 51.
    A deeper look Type functionality f1 f2 f3 tree-map GeneralTree X X X YetAnotherType X BinaryTree X X
  • 52.
    A deeper look Type functionality f1 f2 f3 tree-map GeneralTree X X X YetAnotherType X BinaryTree X X New column header (API)
  • 53.
    A deeper look Type functionality f1 f2 f3 tree-map GeneralTree X X X YetAnotherType X BinaryTree X X New column header (API) Two implementations
  • 54.
    A deeper look Type functionality f1 f2 f3 tree-map GeneralTree X X X YetAnotherType X BinaryTree X X New column header (API) Two implementations QuadTree
  • 55.
    A deeper look Type functionality f1 f2 f3 tree-map GeneralTree X X X YetAnotherType X BinaryTree X X New column header (API) Two implementations QuadTree ?
  • 56.
    A deeper look Type functionality f1 f2 f3 tree-map GeneralTree X X X YetAnotherType X BinaryTree X X New column header (API) Two implementations QuadTree ? Tree-map did too much!!!
  • 57.
    In the softwarematrix: Need to decomplect the creation of columns headers from cell marking Or in software design language: We need to separate the definition of an API from its implementation
  • 58.
    Creating abstract APIs •No concrete implementation • Define a semantic unit – A set of behaviors that compose an API • In another place define the mapping between data types and the API – Marking of a cell in the matrix
  • 59.
    Protocol • A setof several function signatures – Just the signature, without implementation – Dispatch is done based on the run-time type
  • 60.
    Protocol • A setof several function signatures – Just the signature, without implementation – Dispatch is done based on the run-time type The protocol name
  • 61.
    Protocol • A setof several function signatures – Just the signature, without implementation – Dispatch is done based on the run-time type The protocol name A function signature (there can be several of these)
  • 62.
    Protocols and types •The linking of a protocol to a type can be done not as part of the definition of the type • This results in the possibility to extend existing, compiled types – Extend String – Extend even nil
  • 67.
    Added to anexisting type a new API Without changing the type
  • 68.
    Added to anexisting type a new API Without changing the type Functional polymorphism
  • 69.
    Still, there arelimitations Protocols allow type based dispatch only
  • 70.
    Multi methods • Polymorphismwhich is based on a user defined dispatching function • The result of the execution of the dispatch function determines which implementation will be executes
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 77.
  • 78.
  • 79.
  • 80.
  • 83.
  • 84.
    Multi method • Wecan use the same API for different data elements • All we need to know is that they obey that API • We can introduce new APIs for existing types
  • 85.
    Multi method • Wecan use the same API for different data elements • All we need to know is that they obey that API • We can introduce new APIs for existing types Functional polymorphism
  • 86.
    Is-a relationship • Wecan define that A is-a B • The dispatcher would handle A the same way that it handles B • (derive ::A ::B) – if the dispatch function return ::A – if no value is found for ::A in the dispatcher – Handle it as ::B
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
    Why did itwork • Derive harms the referential transparency of the multi method – The return value may differ if (derive…) was called – Referential transparency is our friend • Derive works only with namespace bound keywords – Those that start with :: • Clojure localizes the effect of mutability to the namespace
  • 94.
    Type functionality f1 f2f3 f4 T1 X X T2 X T3 X T4 X X X X T4 isa T2 (for f2) T4 isa T3 (for f3)
  • 95.
    Type functionality f1 f2f3 f4 T1 X X T2 X T3 X T4 X X X X T4 isa T2 (for f2) T4 isa T3 (for f3) Functional inheritance
  • 96.
    Summary • We’ve seen –Functional abstraction – Functional information hiding – Functional polymorphism – Functional inheritance
  • 97.
    Summary • We’ve seenfunctional – Abstraction – Information hiding – Polymorphism – Inheritance
  • 98.
  • 99.
    Summary • We’ve seenfunctional OOP Clojure Style
  • 100.