Continuations

83
Continuations & Web Applications -Balaji Damodaran, ThoughtWorks

Transcript of Continuations

Page 1: Continuations

Continuations & Web Applications

-Balaji Damodaran, ThoughtWorks

Page 2: Continuations
Page 3: Continuations
Page 4: Continuations

Contiuation

● Continuation is Time Travel

● Continuation is saving the control flow of a program's execution

Page 5: Continuations
Page 6: Continuations

class ControlCentre

def exploreTerrainmarsPlateau = Plateau.new(5, 5)alpha = Rover.new("alpha")source = Position.new(1, 2, "N")alpha.land(marsPlateau, source)destination = alpha.explore("LMLMLMLMM")print destination

endend

Page 7: Continuations

class ControlCentre

def exploreTerrainmarsPlateau = Plateau.new(5, 5)alpha = Rover.new("alpha")source = Position.new(1, 2, "N")alpha.land(marsPlateau, source)destination = alpha.explore("LMLMLMLMM")print destination

endend

Page 8: Continuations

class ControlCentre

def exploreTerrainmarsPlateau = Plateau.new(5, 5)alpha = Rover.new("alpha")source = Position.new(1, 2, "N")alpha.land(marsPlateau, source)destination = alpha.explore("LMLMLMLMM")print destination

endend

Control Scope

Execution Context

marsPlateau

alpha

Page 9: Continuations

class ControlCentre

def exploreTerrainmarsPlateau = Plateau.new(5, 5)alpha = Rover.new("alpha")source = Position.new(1, 2, "N")alpha.land(marsPlateau, source)destination = alpha.explore("LMLMLMLMM")print destination

endend

Control Scope

Execution Context

marsPlateau

alpha

Current Continuation

source = Position.new(1, 2, "N")alpha.land(marsPlateau, source)destination = alpha.explore("LMLMLMLMM")print destination

Page 10: Continuations

class ControlCentre

def exploreTerrainmarsPlateau = Plateau.new(5, 5)alpha = Rover.new("alpha")callcc{|@cc|}callcc{|@cc|}source = Position.new(1, 2, "N")alpha.land(marsPlateau, source)destination = alpha.explore("LMLMLMLMM")print destinationreturn @ccreturn @cc

endend

Page 11: Continuations

class ControlCentre

def exploreTerrainmarsPlateau = Plateau.new(5, 5)alpha = Rover.new("alpha")callcc{|@cc|}callcc{|@cc|}source = Position.new(1, 2, "N")alpha.land(marsPlateau, source)destination = alpha.explore("LMLMLMLMM")print destinationreturn @ccreturn @cc

endend

> c = exploreTerrain“1 3 N”=> #<Continuation:0xb744a8c4>

> c.call“1 3 N”=> #<Continuation:0xb744a8c4>

Page 12: Continuations

Normal Control Flow

Control Flow withContinuations

continuation

Continuation invoked

continuation

Page 13: Continuations

Isn't that just a glorified GOTO?

Page 14: Continuations

class ControlCentre

def exploreTerrainmarsPlateau = Plateau.new(5, 5)alpha = Rover.new("alpha")c = nilc = nilsourcesource == callcc do |cc| callcc do |cc|

c = cc c = cc Position.new(1, 2, "N")

endendalpha.land(marsPlateau, source)destination = alpha.explore("LMLMLMLMM")print destinationreturn creturn c

endend

> c = exploreTerrain“1 3 N”=> #<Continuation:0xb7466240>

> c.call(Position.new(2, 3, “E”))“2 4 E”=> #<Continuation:0xb7466240>

Page 15: Continuations

Normal Control Flow

Control Flow withContinuations

continuation

Continuation invokedwith different parameters

continuationWith different parameters

Page 16: Continuations

def continuationputs "i do some computation " +

"& save the state of execution."m = callcc { |cc| return cc }puts "then i restart the execution from " +

"the saved state & pass custom " + "values such as \"#{m[0]}\" and \"#{m[1]}\""

end

> c = continuation

i do some computation & save the state of execution.

> c.call("so..", "then..")

then i restart the execution from the saved state & pass custom values such as "so.." and "then.."

Page 17: Continuations

Normal Control Flow

Control Flow withContinuations paused

continuation

Continuation reinvokedwith parameters

continuationWith parameters

Page 18: Continuations
Page 19: Continuations

Continuation?

● A continuation reifies the control flow of a program as just another data value

● Reify – To consider an abstract concept to be real. To make control flow as first class functions/objects.

Page 20: Continuations

Continuation

● Continuation is an object that takes a snapshot copy of the running process.

● The current process is copied and saved.

● Current process – execution context and all local variables

Page 21: Continuations

Normal Control Flow

Control Flow marked with continuation

#

continuation

Memory

Local variables

Page 22: Continuations

A new process that invokes a continuation

#

Memory

The current execution is abandoned

Note: Global data does not get stored in a continuation

Page 23: Continuations

Continuations

● A Continuation stores the execution context, its references and pointers.

● However, it does not store the heap data or data that is outside the scope of local references and pointers.

● So any change made to them will stay changed even after invoking the continuation.

Page 24: Continuations

Continuations Sandwich Analogy

Page 25: Continuations
Page 26: Continuations

call-with-current-continuation

● call-with-current-continuation, in short called as “call/cc” is a procedure first introduced in Scheme.

● Now exists in several other programming languages such as Ruby, known as “callcc”

Page 27: Continuations

call-with-current-continuation

● call/cc takes in only one argument, which is a function f.

● It takes the current continuation as an object and applies f to it.

– continuation = new Continuation()

– function(continuation)

● When, callcc gets invoked, the program flow will continue from the point it was captured and the argument to the continuation will become its return value

Page 28: Continuations

Method definition:function: call/cc(function: f) {

c = new: Continuationf(c)

}

JavaScript (Rhino):function callcc(f) {

var c = new Continuation();return f(c);

}

Ruby:callcc {|cont|} cont => Continuation objectcont.call(*args)

call-with-current-continuation

Page 29: Continuations

call-with-current-continuationfunction callcc(fun) {

var continuation = new Continuation()return fun(continuation)

}

var ccprint(3 * (8 + callcc(function(c) {

cc = creturn 4

})))

js> 36

Page 30: Continuations

call-with-current-continuationfunction callcc(fun) {

var continuation = new Continuation()return fun(continuation)

}

var ccprint(3 * (8 + callcc(function(c) {

cc = creturn 4

})))

js> 36

js> cc(6)42

Page 31: Continuations

def continue_example i = 0 print "Before callcc #{i}\n" callcc do |cc| for i in 1..10 do print "In callcc #{i}\n" return cc if i > 5 end end print "After callcc #{i}\n"end

Page 32: Continuations

def continue_example i = 0 print "Before callcc #{i}\n" callcc do |cc| for i in 1..10 do print "In callcc #{i}\n" return cc if i > 5 end end print "After callcc #{i}\n"end

puts "begin control flow."c = continue_example()puts "after invoking the method"if c c.call puts "this will not get executed"end

Page 33: Continuations

def continue_example i = 0 print "Before callcc #{i}\n" callcc do |cc| for i in 1..10 do print "In callcc #{i}\n" return cc if i > 5 end end print "After callcc #{i}\n"end

puts "begin control flow."c = continue_example()puts "after invoking the method"if c c.call puts "this will not get executed"end

begin control flow.Before callcc 0In callcc 1In callcc 2In callcc 3In callcc 4In callcc 5In callcc 6after invoking the methodAfter callcc 6after invoking the method

Page 34: Continuations

call-with-current-continuation

● Continuations are sort of goto labels. But more powerful.● We can store the continuation in a variable or

object field, unlike a goto label.● Goto labels are restricted within a functional

scope, continuations are not limited by that.

Page 35: Continuations

The following code is strictly for session purposes only. Implementing this in usable code may cause

harm to life and limb.

Page 36: Continuations

Continuation as a GOTOdef goto_in_ruby_1 i = 0 callcc {|@label|} i = i + 1 print "#{i}\t" @label.call if i < 10end

Page 37: Continuations

Continuation as a GOTOdef goto_in_ruby_1 i = 0 callcc {|@label|} i = i + 1 print "#{i}\t" @label.call if i < 10end

output:1 2 3 4 5 6 7 8 9 10

Page 38: Continuations

Continuation as a GOTOdef goto_in_ruby_1 i = 0 callcc {|@label|} i = i + 1 print "#{i}\t" @label.call if i < 10end

output:1 2 3 4 5 6 7 8 9 10

def goto_in_ruby_2 i = 0 callcc do |label| label.call

i = 99endprint i

end

Page 39: Continuations

Continuation as a GOTOdef goto_in_ruby_1 i = 0 callcc {|@label|} i = i + 1 print "#{i}\t" @label.call if i < 10end

output:1 2 3 4 5 6 7 8 9 10

def goto_in_ruby_2 i = 0 callcc do |label| label.call

i = 99endprint i

end

output:0

Page 40: Continuations

Summary

● Continuation is a procedure that represents the remaining steps in a computation.

● It is a "snapshot" of the current control context or control state of the program

● The continuation can be later invoked (repeatedly) with custom arguments

Page 41: Continuations

Continuations

● Languages that support first class continuations● Scheme (call/cc)● Ruby (callcc)● Smalltalk (Continuation currentDo:)● Rhino [JavaScript] (new Continuation())● Scala (Responder & shift, reset)● Perl (Coro)● Haskell (Control.Monad.Cont)

Page 42: Continuations

Continuations Types

● First class continuations● Continuation Passing Style (CPS)● Delimited Continuations

Page 43: Continuations
Page 44: Continuations

Continuation Passing Style

● A function, instead of returning an explict value, it takes an explict 'continuation' argument – another function which is meant to receive the result of the computation

Page 45: Continuations

Continuation Passing Style

function (arg) {//computationreturn result;

}

function (arg, k) {//computationk(result);

}

Page 46: Continuations

function add(x, y) {return x + y

}

function square(x) {return x * x

}

function calculate(x, y) {return add(square(x), square(y))

}

js> print(calculate(3, 4))=> 25

CPS - Example

Page 47: Continuations

function add_cps(x, y, c) {c(x + y)

}

function square_cps(x, c) {c(x * x)

}

CPS - Example

Page 48: Continuations

function add_cps(x, y, c) {c(x + y)

}

function square_cps(x, c) {c(x * x)

}

function calculate_cps(x, y, c) {square_cps(x, function(v) {

square_cps(y, function(r){add_cps(v,r,c)

})})

}

CPS - Example

Page 49: Continuations

function add_cps(x, y, c) {c(x + y)

}

function square_cps(x, c) {c(x * x)

}

function calculate_cps(x, y, c) {square_cps(x, function(v) {

square_cps(y, function(r){add_cps(v,r,c)

})})

}

js> calculate_cps(3, 4, print)=> 25js> calculate_cps(3, 4, function(v) {print(sqrt(v))});=> 5

CPS - Example

Page 50: Continuations

CPS

● CPS is used in programming languages that do not have first – class continuations, but have first – class functions

● Every call is a tail call and if used without Tail Call Optimization (TCO), the continuation would grow during recursion

● Using CPS and TCO, compilers and interperters of some programming languages managed to eliminate the need for a runtime stack.

Page 51: Continuations
Page 52: Continuations

Delimited Continuations

● Delimited (or partial, or composable) continuations are more like regular functions and less like GOTOs. They do not embody the entire rest of the computation, but just a partial rest, up to a programmer-defined outer bound.

● delimited continuations will return control to the caller

after they are invoked, and they may also return values

– Tiark Rompf, Ingo Maier, Martin Odersky

Page 53: Continuations

Normal Control Flow

Control Flow withDelimited Continuations

Continuation -start

Continuation invoked

Continuation -end

Continuation -start

Delimitedcontinuation

Page 54: Continuations

Delimited Continuations

● Delimited Continuations are manipulated by means of two primitives, shift and reset.

● Calling shift captures the current continuation, and reset defines the boundary up to which the continuation reaches.

Page 55: Continuations

Delimited Continuationsreset {

shift { k: (Int=>Int) => k(7)

} + 1 } * 2

scala> 16

CPS transformed2 * (1 + 7)

Page 56: Continuations

Delimited Continuationsreset {

shift { k: (Int=>Int) => k(7)

} + 1 } * 2

scala> 16__________________________________________________________

reset {foo() + 1

} * 2

CPS transformed2 * (1 + 7)

def foo() {shift { k: (Int=>Int) =>

k(7)}

}

Page 57: Continuations

Delimited Continuationsreset{

1 + shift{ k: (Int=>Int) => k(k(7))

}} * 3

scala>27

reset{1 + shift{ k: (Int=>Int) =>

k(k(7))} * 3

}

scala>67

Page 58: Continuations

Delimited Continuationsreset{

1 + shift{ k: (Int=>Int) => k(k(7))

}} * 3

scala>27

reset{1 + shift{ k: (Int=>Int) =>

k(k(7))} * 3

}

scala>67

CPS Transform: (1 + (1 + 7)) * 3 = 27CPS Transform: (1 + (1 + 7)) * 3 = 27

CPS Transform: (1 + (1 + 7 * 3) * 3) = 67CPS Transform: (1 + (1 + 7 * 3) * 3) = 67

Page 59: Continuations

So... ummm..Whats the real world use of this thing?

Page 60: Continuations
Page 61: Continuations

Applications of Continuations

● Pause and Play e.g. User Interface design● Backtracking● Coroutines● Exception Handling● Web Frameworks● Compiler & Interpreter implementation

Page 62: Continuations

Problems

● Page centric● HTTP Stateless-ness causes heavy use of

session, cookies● 'Back' button in user interaction pages● Browser cloning in user interaction pages● Inversion of control

Page 63: Continuations

def add_two_numbers n1 = callcc { |cc| return ask("1st number:", cc) } n2 = callcc { |cc| return ask("2nd number:", cc) } print "sum of two numbers is #{n1 + n2}\n"end

Page 64: Continuations

def add_two_numbers n1 = callcc { |cc| return ask("1st number:", cc) } n2 = callcc { |cc| return ask("2nd number:", cc) } print "sum of two numbers is #{n1 + n2}\n"end

irb> add_two_numbers1st number:respond with: submit(25, ...): => #<Continuation:0xb76e0e58>irb> submit(25, 30)2nd number:respond with: submit(37, ...): => #<Continuation:0xb76ddde8>irb> submit(37, 12)sum of two numbers is 42=> nil

Page 65: Continuations

def add_two_numbers n1 = callcc { |cc| return ask("1st number:", cc) } n2 = callcc { |cc| return ask("2nd number:", cc) } print "sum of two numbers is #{n1 + n2}\n"end

@session = Hash.new

def ask(str, cc) r = rand(100).to_i print "#{str}\nrespond with: submit(#{r}, ...): " @session[r] = cc ccend

def submit(id, number) @session[id].call(number)End

Page 66: Continuations

server

call: page acall: page bcall: page c

client

Continuations lookup table (session)

1

2

3

4

Server renders the page and saves the continuation in the session with a uuid

The page is rendered with the uuid given in the

url

Client makes a server response

with required information

The continuation object is looked up based on the uuid

in the url and executed

Page 67: Continuations

Web Frameworks

● Seaside in Smalltalk (v 3.1)● Wee in Ruby (v 2.1)● Nagare in Python (v 0.3)● Apache Cocoon in Java (v 2.2)● RIFE in Java (v 1.6)● Ocsigen in OCaml (v 1.3)● Weblocks in Common Lisp

Page 68: Continuations

Web Servers with Continuations support

● Continuity (Perl)● Jetty 6 (Java)● Plt-Scheme web server (Scheme)

Page 69: Continuations
Page 70: Continuations

Seaside

● Written in Smalltalk

● Often called the 'heretic' framework because it doesn't follow the 'conventional' web wisdom

– Clean urls

– Templates to separate model and view

– Share as little state as possible

– Urls contain session identifiers

– There is no 'view' or html templates. Views are part of smalltalk objects

– Seaside continuations & callbacks give a stateful behavior

Page 71: Continuations

Seaside - Installation

One – click install experience

Page 72: Continuations

Seaside - Workspace

● Smalltalk deals with image snapshots for saving the workspace.

● There is no concept of 'files' and 'editors'

● Class objects are created through 'object browser' and code is executed through a 'workspace'

Page 73: Continuations

Seaside - Components

● Components represent the whole of a page or portion of pages

● The inherit from 'WAComponent' class

● Components maintain state

● Component's response loop– Renders the component

– Waits for user's input

– Executes a block of code when a link or button is pressed

– Re-renders itself or another component in place

Page 74: Continuations

Image from - Seaside – A Multiple Control Flow Web Application Framework, Stephane Ducasse

Page 75: Continuations

Seaside - callbacks

● Every user interaction on the web page triggers a callback.

● A callback can be on a link, button or any other form elements

● The callback will execute a block of code whose result will end in re-rendering the component or a new component

Page 76: Continuations

SimpleCounter>>initialize super initialize. counter := 0.

SimpleCounter>>renderContentOn: html html heading: 'the counter is ', counter asString. html anchor callback: [ counter := counter + 1 ]; with: 'increase'.

Page 77: Continuations

Seaside - Continuations

● Call / Answer● call: takes a component as a parameter and it swaps

the current component for the new component

● The new component will be rendered and user action will cause a callback to run that'll send an answer:

● The value passed to answer: will be returned to call: and the program will continue from there.

Page 78: Continuations

Image from - Seaside – A Multiple Control Flow Web Application Framework, Stephane Ducasse

Page 79: Continuations

Request 1

Response 1

Continuation saved

Request 2

Response 2

Continuation invoked

Problem with full continuation

Page 80: Continuations

Solved with delimited continuation

Request 1

Response 1

DelimitedContinuation saved

Request 2

Response 2

Delimited Continuation invoked

Page 81: Continuations

Challenges

● Understanding continuations as a concept ● Debugging● Buying into the 'heretic' idea

Page 82: Continuations

Seaside – Demo

Page 83: Continuations

References● http://en.wikipedia.org/wiki/Continuation

● http://idea-log.blogspot.com/2005/10/why-are-continuations-so-confusing-and.html

● http://www.iam.unibe.ch/~scg/Archive/Papers/Duca04eSeaside.pdf

● http://vimeo.com/13304075

● http://www.intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons

● http://www.cs.indiana.edu/~dfried/appcont.pdf

● http://lambda-the-ultimate.org/node/86

● http://en.wikipedia.org/wiki/Continuation-passing_style

● http://lamp.epfl.ch/~rompf/continuations-icfp09.pdf

● http://book.seaside.st/book

● http://en.wikipedia.org/wiki/Call-with-current-continuation

● http://www.ibm.com/developerworks/java/library/j-contin.html

● http://www.cs.brown.edu/~sk/Publications/Papers/Published/khmgpf-impl-use-plt-web-server-journal/

● http://double.co.nz/pdf/continuations.pdf