SlideShare a Scribd company logo
Rubyslava / PyVo #32
26.09.2013
Imperative versus Functional Programming
Jan Herich
@janherich
@itedge
Core aspects of
Imperative Programming
Core aspects of
Imperative Programming
● Emphasis on mutable state
➢ In place modification of variables (memory locations)
➢ The flow of the program is determined by directly checking
those memory locations → typical example is imperative
looping : for(int i=1; i<11; i++) { System.out.println("Count is: " + i); }
Core aspects of
Imperative Programming
● Emphasis on mutable state
➢ In place modification of variables (memory locations)
➢ The flow of the program is determined by directly checking
those memory locations → typical example is imperative
looping : for(int i=1; i<11; i++) { System.out.println("Count is: " + i); }
● Rooted in single-threaded premise
➢ Assuming that there is only one thread of execution
➢ So the world is effectively “stopped” when you look at it or
change it
Core aspects of
Imperative Programming
● Emphasis on mutable state
➢ In place modification of variables (memory locations)
➢ The flow of the program is determined by directly checking
those memory locations → typical example is imperative
looping : for(int i=1; i<11; i++) { System.out.println("Count is: " + i); }
● Rooted in single-threaded premise
➢ Assuming that there is only one thread of execution
➢ So the world is effectively “stopped” when you look at it or
change it
● Prevalent in most OO languages
➢ C++, Java, C#, Python, Ruby, etc.
What's wrong with
Imperative programming ?
What's wrong with
Imperative programming ?
● Uncoordinated mutation
➢ No built-in facilities in the language to coordinate changes
➢ It could result in brittle systems, even without concurrency
➢ Add concurrency/parallelism and everything only get worse
What's wrong with
Imperative programming ?
● Uncoordinated mutation
➢ No built-in facilities in the language to coordinate changes
➢ It could result in brittle systems, even without concurrency
➢ Add concurrency/parallelism and everything only get worse
● Complecting the state and identity in OO
➢ Object reference → Identity and value mixed together
➢ Object (identity) is a pointer to the memory that contains the
value of its state
➢ There is no way to observe a stable state (even to copy it)
without blocking others from changing it
➢ There is no way to associate the identity's state with a different
value other than in-place memory mutation
Example of harmful mutation
Our initial objects:
var record1 = {state_id:'S2',county_id:'C1',population:3439,area:97};
var record2 = {state_id:'S5',county_id:'C2',population:85345,area:128};
var record3 = {state_id:'S2',county_id:'C3',population:7435,area:157};
Example of harmful mutation
Reasonably nice function without side effects:
var groupRecords = function(records,key) {
var groups = {};
for (var i = 0; i < records.length; i++) {
var current = records[i];
var keyValue = current[key];
if (!groups.hasOwnProperty(keyValue)) {
groups[keyValue] = [];
}
groups[keyValue].push(current);
}
return groups;
};
Our initial objects:
var record1 = {state_id:'S2',county_id:'C1',population:3439,area:97};
var record2 = {state_id:'S5',county_id:'C2',population:85345,area:128};
var record3 = {state_id:'S2',county_id:'C3',population:7435,area:157};
New grouped datastructure:
var grouped = groupRecords([record1, record2, record3], 'county_id');
Example of harmful mutation
Reasonably nice function without side effects:
var groupRecords = function(records,key) {
var groups = {};
for (var i = 0; i < records.length; i++) {
var current = records[i];
var keyValue = current[key];
if (!groups.hasOwnProperty(keyValue)) {
groups[keyValue] = [];
}
groups[keyValue].push(current);
}
return groups;
};
Ugly side-effect function, written by unexperienced
programmer, who doesn't know much about object
references:
var sumRecords = function(records) {
var first = records[0];
for (var i = 1; i < records.length; i++) {
var current = records[i];
first.population += current.population;
first.area += current.area;
}
return first;
};
Our initial objects:
var record1 = {state_id:'S2',county_id:'C1',population:3439,area:97};
var record2 = {state_id:'S5',county_id:'C2',population:85345,area:128};
var record3 = {state_id:'S2',county_id:'C3',population:7435,area:157};
New grouped datastructure:
var grouped = groupRecords([record1, record2, record3], 'county_id');
We don't expect that this function call will mutate the former object record1:
var state2summed = sumRecords(grouped.S2);
How can we do better ?
How can we do better ?
● What if every datastructure in your program would be immutable ?
➢ It would solve our problem with leaking mutable references
all over the codebase
How can we do better ?
● What if every datastructure in your program would be immutable ?
➢ It would solve our problem with leaking mutable references
all over the codebase
● But how can we model any progress if everything is static ?
➢ It's nice to be safe, but how can we actually accomplish anything
if everything is immutable so we can't change it ? It turns out we
can, if we use persistent data structures → that we can't change
something in place doesn't mean that we can't model progress
How can we do better ?
● What if every datastructure in your program would be immutable ?
➢ It would solve our problem with leaking mutable references
all over the codebase
● But how can we model any progress if everything is static ?
➢ It's nice to be safe, but how can we actually accomplish anything
if everything is immutable so we can't change it ? It turns out we
can, if we use persistent data structures → that we can't change
something in place doesn't mean that we can't model progress
● What is a persistent data structure ?
➢ Persistent data structure is a data structure that always preserves
the previous version of itself when it is modified. Such data
structures are effectively immutable, as their operations do not
(visibly) update the structure in-place, but instead always yield a
new updated structure
How persistent data structures work
● Creation of new
datastructures must be fast
and efficient.
● This is achieved by structural
sharing
● Obviously, the garbage
collection is a must in this
case
xs
d
b g
a c f h
ys
d'
g'
f'
e
Our example revisited
Our initial references to VALUES:
(def record-1 {:state-id "S2" :county-id "C1" :population 3439 :area 97})
(def record-2 {:state-id "S5" :county-id "C2" :population 85345 :area 128})
(def record-3 {:state-id "S2" :county-id "C3" :population 7435 :area 157})
Our example revisited
(defn group-records [records key]
(reduce (fn [accumulator record]
(let [key-val (get record key)
subrecords (get accumulator key-val [])]
(assoc accumulator key-val (conj subrecords record))))
{}
records))
Our initial references to VALUES:
(def record-1 {:state-id "S2" :county-id "C1" :population 3439 :area 97})
(def record-2 {:state-id "S5" :county-id "C2" :population 85345 :area 128})
(def record-3 {:state-id "S2" :county-id "C3" :population 7435 :area 157})
New merged VALUE:
(def grouped (group-records [record-1 record-2 record-3] :state-id))
Our example revisited
(defn group-records [records key]
(reduce (fn [accumulator record]
(let [key-val (get record key)
subrecords (get accumulator key-val [])]
(assoc accumulator key-val (conj subrecords record))))
{}
records))
Our inexperienced programmer
and his function again:
(defn alter-records [records]
;; the first record remains unchaged
;; because it is a reference
;; to value, and values don't
;; change :)
(assoc (first records) :population 0))
Our initial references to VALUES:
(def record-1 {:state-id "S2" :county-id "C1" :population 3439 :area 97})
(def record-2 {:state-id "S5" :county-id "C2" :population 85345 :area 128})
(def record-3 {:state-id "S2" :county-id "C3" :population 7435 :area 157})
New merged VALUE:
(def grouped (group-records [record-1 record-2 record-3] :state-id))
We created new VALUE state-2-altered, but our record-1
remains unchanged, even if those two VALUES partially
share their structure:
(def state-2-altered (alter-records (grouped "S2")))
Key points from our
Imperative/Functional comparision
● In our imperative example, we created many
more identities then we really needed.
● The identities we created (record1, record2,
record2) would be better modeled as values
instead.
● The value of values should not be
undervalued :)
But what if we really need
identities ?
● Most programs need identities
➢ There are programs resembling huge functions such as
compilers, but most other programs need to model identities
● It's worthwhile to separate identity and state
➢ Instead of thinking about identity states as a contents of the
particular memory block, it's better to think about it as a value
currently associated with the identity
➢ The identity can be in different states in different times, but the
state itself doesn't change
➢ Thus, the identity is not a state, the identity has a state, exactly
one at any point of time
How do we model identities ?
● We need atomic references to values
➢ Because every 'value-swap' of the identity (remember, every
identity has a state, which is immutable value) needs to be
atomic (similar to atomic database commits, always resulting in
consistent database state)
➢ In Clojure, those changes to references are controlled and
coordinated by the system – so the cooperation is not optional
and not manual
➢ The world moves forward due to the cooperative efforts of its
participants and the programming language/system, Clojure, is
in charge of world consistency management. The value of a
reference (state of an identity) is always observable without
coordination, and freely shareable between threads
Example of atomic reference in
Clojure
We define out initial cache data:
(def initial-data ["D1" "D2" "D3"])
Now we create an special atomic reference – named cache:
(def cache (atom initial-data))
We read the cache into some intermediate variable:
(def cache-data (deref cache))
The result is true:
(= initial-data cache-data)
We swap the cache for different value -> we add "D4" and "D5" in this case:
(swap! cache conj ["D4" "D5"])
Whenever the cache is dereferenced, we get the new data:
(deref cache)
But the former cache reading cache-data is still unchanged, so this remains true:
(= initial-data cache-data)
There is a lot more to discover
● There are more reference types in Clojure, but that is out of
scope of this talk
● And of course not only that, there are many, many more cool
features in Clojure which you wouldn't find in other languages
such as for example multimethods or true macros for
metaprogramming
● Visit http://clojure.org/ to learn more

More Related Content

PPTX
Real Object-Oriented Programming: Empirically Validated Benefits of the DCI P...
ODP
Data repositories
PDF
React in 45 Minutes (Jfokus)
PPTX
Zookeeper Architecture
PDF
The Newest in Session Types
PPTX
React tips
PDF
How and why I turned my old Java projects into a first-class serverless compo...
PPTX
Cassandra Architecture
Real Object-Oriented Programming: Empirically Validated Benefits of the DCI P...
Data repositories
React in 45 Minutes (Jfokus)
Zookeeper Architecture
The Newest in Session Types
React tips
How and why I turned my old Java projects into a first-class serverless compo...
Cassandra Architecture

Similar to Rubyslava slides-26.09.2013 (20)

PDF
Value Objects
PDF
Persistent Data Structures by @aradzie
PDF
Functional Programming with Immutable Data Structures
PDF
Hickey jvm summit2009
PDF
If You Think You Can Stay Away from Functional Programming, You Are Wrong
PDF
Persistent Data Structures And Managed References
PPT
Clojure slides
PDF
Functional programming with clojure
PDF
functional groovy
KEY
LISP: How I Learned To Stop Worrying And Love Parantheses
PDF
Why we cannot ignore Functional Programming
PPTX
Столпы функционального программирования для адептов ООП, Николай Мозговой
PDF
(6) collections algorithms
PDF
immutability changes everything and xyzwert
PPTX
Into the Land of lambda, One Programmer's Journey Into Functional Programming
PPTX
Functional Programming in Javascript - IL Tech Talks week
PDF
DEF CON 27 - workshop - EIGENTOURIST - hacking with monads
PDF
GoshawkDB: Making Time with Vector Clocks
PDF
Tech Talk - Immutable Data Structure
PPTX
Immutable data structures - A Primer
Value Objects
Persistent Data Structures by @aradzie
Functional Programming with Immutable Data Structures
Hickey jvm summit2009
If You Think You Can Stay Away from Functional Programming, You Are Wrong
Persistent Data Structures And Managed References
Clojure slides
Functional programming with clojure
functional groovy
LISP: How I Learned To Stop Worrying And Love Parantheses
Why we cannot ignore Functional Programming
Столпы функционального программирования для адептов ООП, Николай Мозговой
(6) collections algorithms
immutability changes everything and xyzwert
Into the Land of lambda, One Programmer's Journey Into Functional Programming
Functional Programming in Javascript - IL Tech Talks week
DEF CON 27 - workshop - EIGENTOURIST - hacking with monads
GoshawkDB: Making Time with Vector Clocks
Tech Talk - Immutable Data Structure
Immutable data structures - A Primer
Ad

Recently uploaded (20)

PDF
Encapsulation theory and applications.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
cuic standard and advanced reporting.pdf
PPTX
Big Data Technologies - Introduction.pptx
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
Cloud computing and distributed systems.
PDF
Approach and Philosophy of On baking technology
PDF
Empathic Computing: Creating Shared Understanding
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
Spectroscopy.pptx food analysis technology
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
Encapsulation theory and applications.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
cuic standard and advanced reporting.pdf
Big Data Technologies - Introduction.pptx
Encapsulation_ Review paper, used for researhc scholars
Per capita expenditure prediction using model stacking based on satellite ima...
Cloud computing and distributed systems.
Approach and Philosophy of On baking technology
Empathic Computing: Creating Shared Understanding
Programs and apps: productivity, graphics, security and other tools
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Spectroscopy.pptx food analysis technology
Reach Out and Touch Someone: Haptics and Empathic Computing
NewMind AI Weekly Chronicles - August'25-Week II
Network Security Unit 5.pdf for BCA BBA.
The Rise and Fall of 3GPP – Time for a Sabbatical?
Mobile App Security Testing_ A Comprehensive Guide.pdf
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Unlocking AI with Model Context Protocol (MCP)
Ad

Rubyslava slides-26.09.2013

  • 1. Rubyslava / PyVo #32 26.09.2013 Imperative versus Functional Programming Jan Herich @janherich @itedge
  • 3. Core aspects of Imperative Programming ● Emphasis on mutable state ➢ In place modification of variables (memory locations) ➢ The flow of the program is determined by directly checking those memory locations → typical example is imperative looping : for(int i=1; i<11; i++) { System.out.println("Count is: " + i); }
  • 4. Core aspects of Imperative Programming ● Emphasis on mutable state ➢ In place modification of variables (memory locations) ➢ The flow of the program is determined by directly checking those memory locations → typical example is imperative looping : for(int i=1; i<11; i++) { System.out.println("Count is: " + i); } ● Rooted in single-threaded premise ➢ Assuming that there is only one thread of execution ➢ So the world is effectively “stopped” when you look at it or change it
  • 5. Core aspects of Imperative Programming ● Emphasis on mutable state ➢ In place modification of variables (memory locations) ➢ The flow of the program is determined by directly checking those memory locations → typical example is imperative looping : for(int i=1; i<11; i++) { System.out.println("Count is: " + i); } ● Rooted in single-threaded premise ➢ Assuming that there is only one thread of execution ➢ So the world is effectively “stopped” when you look at it or change it ● Prevalent in most OO languages ➢ C++, Java, C#, Python, Ruby, etc.
  • 7. What's wrong with Imperative programming ? ● Uncoordinated mutation ➢ No built-in facilities in the language to coordinate changes ➢ It could result in brittle systems, even without concurrency ➢ Add concurrency/parallelism and everything only get worse
  • 8. What's wrong with Imperative programming ? ● Uncoordinated mutation ➢ No built-in facilities in the language to coordinate changes ➢ It could result in brittle systems, even without concurrency ➢ Add concurrency/parallelism and everything only get worse ● Complecting the state and identity in OO ➢ Object reference → Identity and value mixed together ➢ Object (identity) is a pointer to the memory that contains the value of its state ➢ There is no way to observe a stable state (even to copy it) without blocking others from changing it ➢ There is no way to associate the identity's state with a different value other than in-place memory mutation
  • 9. Example of harmful mutation Our initial objects: var record1 = {state_id:'S2',county_id:'C1',population:3439,area:97}; var record2 = {state_id:'S5',county_id:'C2',population:85345,area:128}; var record3 = {state_id:'S2',county_id:'C3',population:7435,area:157};
  • 10. Example of harmful mutation Reasonably nice function without side effects: var groupRecords = function(records,key) { var groups = {}; for (var i = 0; i < records.length; i++) { var current = records[i]; var keyValue = current[key]; if (!groups.hasOwnProperty(keyValue)) { groups[keyValue] = []; } groups[keyValue].push(current); } return groups; }; Our initial objects: var record1 = {state_id:'S2',county_id:'C1',population:3439,area:97}; var record2 = {state_id:'S5',county_id:'C2',population:85345,area:128}; var record3 = {state_id:'S2',county_id:'C3',population:7435,area:157}; New grouped datastructure: var grouped = groupRecords([record1, record2, record3], 'county_id');
  • 11. Example of harmful mutation Reasonably nice function without side effects: var groupRecords = function(records,key) { var groups = {}; for (var i = 0; i < records.length; i++) { var current = records[i]; var keyValue = current[key]; if (!groups.hasOwnProperty(keyValue)) { groups[keyValue] = []; } groups[keyValue].push(current); } return groups; }; Ugly side-effect function, written by unexperienced programmer, who doesn't know much about object references: var sumRecords = function(records) { var first = records[0]; for (var i = 1; i < records.length; i++) { var current = records[i]; first.population += current.population; first.area += current.area; } return first; }; Our initial objects: var record1 = {state_id:'S2',county_id:'C1',population:3439,area:97}; var record2 = {state_id:'S5',county_id:'C2',population:85345,area:128}; var record3 = {state_id:'S2',county_id:'C3',population:7435,area:157}; New grouped datastructure: var grouped = groupRecords([record1, record2, record3], 'county_id'); We don't expect that this function call will mutate the former object record1: var state2summed = sumRecords(grouped.S2);
  • 12. How can we do better ?
  • 13. How can we do better ? ● What if every datastructure in your program would be immutable ? ➢ It would solve our problem with leaking mutable references all over the codebase
  • 14. How can we do better ? ● What if every datastructure in your program would be immutable ? ➢ It would solve our problem with leaking mutable references all over the codebase ● But how can we model any progress if everything is static ? ➢ It's nice to be safe, but how can we actually accomplish anything if everything is immutable so we can't change it ? It turns out we can, if we use persistent data structures → that we can't change something in place doesn't mean that we can't model progress
  • 15. How can we do better ? ● What if every datastructure in your program would be immutable ? ➢ It would solve our problem with leaking mutable references all over the codebase ● But how can we model any progress if everything is static ? ➢ It's nice to be safe, but how can we actually accomplish anything if everything is immutable so we can't change it ? It turns out we can, if we use persistent data structures → that we can't change something in place doesn't mean that we can't model progress ● What is a persistent data structure ? ➢ Persistent data structure is a data structure that always preserves the previous version of itself when it is modified. Such data structures are effectively immutable, as their operations do not (visibly) update the structure in-place, but instead always yield a new updated structure
  • 16. How persistent data structures work ● Creation of new datastructures must be fast and efficient. ● This is achieved by structural sharing ● Obviously, the garbage collection is a must in this case xs d b g a c f h ys d' g' f' e
  • 17. Our example revisited Our initial references to VALUES: (def record-1 {:state-id "S2" :county-id "C1" :population 3439 :area 97}) (def record-2 {:state-id "S5" :county-id "C2" :population 85345 :area 128}) (def record-3 {:state-id "S2" :county-id "C3" :population 7435 :area 157})
  • 18. Our example revisited (defn group-records [records key] (reduce (fn [accumulator record] (let [key-val (get record key) subrecords (get accumulator key-val [])] (assoc accumulator key-val (conj subrecords record)))) {} records)) Our initial references to VALUES: (def record-1 {:state-id "S2" :county-id "C1" :population 3439 :area 97}) (def record-2 {:state-id "S5" :county-id "C2" :population 85345 :area 128}) (def record-3 {:state-id "S2" :county-id "C3" :population 7435 :area 157}) New merged VALUE: (def grouped (group-records [record-1 record-2 record-3] :state-id))
  • 19. Our example revisited (defn group-records [records key] (reduce (fn [accumulator record] (let [key-val (get record key) subrecords (get accumulator key-val [])] (assoc accumulator key-val (conj subrecords record)))) {} records)) Our inexperienced programmer and his function again: (defn alter-records [records] ;; the first record remains unchaged ;; because it is a reference ;; to value, and values don't ;; change :) (assoc (first records) :population 0)) Our initial references to VALUES: (def record-1 {:state-id "S2" :county-id "C1" :population 3439 :area 97}) (def record-2 {:state-id "S5" :county-id "C2" :population 85345 :area 128}) (def record-3 {:state-id "S2" :county-id "C3" :population 7435 :area 157}) New merged VALUE: (def grouped (group-records [record-1 record-2 record-3] :state-id)) We created new VALUE state-2-altered, but our record-1 remains unchanged, even if those two VALUES partially share their structure: (def state-2-altered (alter-records (grouped "S2")))
  • 20. Key points from our Imperative/Functional comparision ● In our imperative example, we created many more identities then we really needed. ● The identities we created (record1, record2, record2) would be better modeled as values instead. ● The value of values should not be undervalued :)
  • 21. But what if we really need identities ? ● Most programs need identities ➢ There are programs resembling huge functions such as compilers, but most other programs need to model identities ● It's worthwhile to separate identity and state ➢ Instead of thinking about identity states as a contents of the particular memory block, it's better to think about it as a value currently associated with the identity ➢ The identity can be in different states in different times, but the state itself doesn't change ➢ Thus, the identity is not a state, the identity has a state, exactly one at any point of time
  • 22. How do we model identities ? ● We need atomic references to values ➢ Because every 'value-swap' of the identity (remember, every identity has a state, which is immutable value) needs to be atomic (similar to atomic database commits, always resulting in consistent database state) ➢ In Clojure, those changes to references are controlled and coordinated by the system – so the cooperation is not optional and not manual ➢ The world moves forward due to the cooperative efforts of its participants and the programming language/system, Clojure, is in charge of world consistency management. The value of a reference (state of an identity) is always observable without coordination, and freely shareable between threads
  • 23. Example of atomic reference in Clojure We define out initial cache data: (def initial-data ["D1" "D2" "D3"]) Now we create an special atomic reference – named cache: (def cache (atom initial-data)) We read the cache into some intermediate variable: (def cache-data (deref cache)) The result is true: (= initial-data cache-data) We swap the cache for different value -> we add "D4" and "D5" in this case: (swap! cache conj ["D4" "D5"]) Whenever the cache is dereferenced, we get the new data: (deref cache) But the former cache reading cache-data is still unchanged, so this remains true: (= initial-data cache-data)
  • 24. There is a lot more to discover ● There are more reference types in Clojure, but that is out of scope of this talk ● And of course not only that, there are many, many more cool features in Clojure which you wouldn't find in other languages such as for example multimethods or true macros for metaprogramming ● Visit http://clojure.org/ to learn more