Continuations

Post on 15-Jul-2015

1.342 views 1 download

Transcript of Continuations

Continuations & Web Applications

-Balaji Damodaran, ThoughtWorks

Contiuation

● Continuation is Time Travel

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

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

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

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

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

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

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>

Normal Control Flow

Control Flow withContinuations

continuation

Continuation invoked

continuation

Isn't that just a glorified GOTO?

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>

Normal Control Flow

Control Flow withContinuations

continuation

Continuation invokedwith different parameters

continuationWith different parameters

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.."

Normal Control Flow

Control Flow withContinuations paused

continuation

Continuation reinvokedwith parameters

continuationWith parameters

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.

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

Normal Control Flow

Control Flow marked with continuation

#

continuation

Memory

Local variables

A new process that invokes a continuation

#

Memory

The current execution is abandoned

Note: Global data does not get stored in a continuation

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.

Continuations Sandwich Analogy

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”

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

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

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

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

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

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

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

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.

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

harm to life and limb.

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

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

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

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

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

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)

Continuations Types

● First class continuations● Continuation Passing Style (CPS)● Delimited 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

Continuation Passing Style

function (arg) {//computationreturn result;

}

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

}

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

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

}

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

}

CPS - Example

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

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

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.

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

Normal Control Flow

Control Flow withDelimited Continuations

Continuation -start

Continuation invoked

Continuation -end

Continuation -start

Delimitedcontinuation

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.

Delimited Continuationsreset {

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

} + 1 } * 2

scala> 16

CPS transformed2 * (1 + 7)

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)}

}

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

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

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

Applications of Continuations

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

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

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

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

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

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

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

Web Servers with Continuations support

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

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

Seaside - Installation

One – click install experience

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'

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

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

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

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

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

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.

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

Request 1

Response 1

Continuation saved

Request 2

Response 2

Continuation invoked

Problem with full continuation

Solved with delimited continuation

Request 1

Response 1

DelimitedContinuation saved

Request 2

Response 2

Delimited Continuation invoked

Challenges

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

Seaside – Demo

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