CSC/ECE 517 Fall 2007/wiki1 2 pk: Difference between revisions
No edit summary |
|||
(24 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
= Callbacks = | |||
A callback is code that is passed as an argument to other code. The exact behavior of a callback can be | A callback is code that is passed as an argument to other code. The exact behavior of a callback can be determined at runtime by passing different (yet compatible) function pointers or handles thereby uncoupling the caller from the callee. This makes callbacks easier to use than polymorphism and generic programming. | ||
Statically scoped languages like C or C++, implement callbacks using references or pointers to code and data outside its own scope. Dynamically scoped languages (like Ruby and Smalltalk) use closures to access application data. | |||
== Closures == | == Closures == | ||
Closures are functions which are evaluated in an environment containing bound variables. They are blocks of code which meets three criteria: | Closures are functions which are evaluated in an environment containing bound variables. They are blocks of code which meets three criteria: | ||
* They can be passed around as a value | * They can be passed around as a value. | ||
* They can be executed on demand | * They can be executed on demand. | ||
* They can refer to variables from the context in which it was created | * They can refer to variables from the context in which it was created. | ||
Closures were initally developed in the 1960s in a language called Scheme and later adopted in other languages including Ruby and Smalltalk. | Closures were initally developed in the 1960s in a language called Scheme and later adopted in other languages including Ruby and Smalltalk. | ||
= Examples = | === Examples === | ||
The code below illustrates a simple case of closure use. | The code below illustrates a simple case of closure use. | ||
Line 32: | Line 32: | ||
The closure(or block) ''{ x+=1 }'' is passed as a parameter to the function ''thrice''. The value of ''x'' before ''thrice'' is called is '''5'''. On execution the value becomes '''8''' i.e. the block ''{x+=1}'' was executed thrice. | The closure(or block) ''{ x+=1 }'' is passed as a parameter to the function ''thrice''. The value of ''x'' before ''thrice'' is called is '''5'''. On execution the value becomes '''8''' i.e. the block ''{x+=1}'' was executed thrice. | ||
Blocks are essentially chunks of code which can be passed around as arguments to functions where they can be invoked any number of times. Note that all blocks are closures, however the reverse may not always be true because closures can refer to the variables which were visible in the lexical environment of the function in which they were defined. | |||
<pre> | <pre> | ||
Line 41: | Line 40: | ||
end | end | ||
</pre> | </pre> | ||
Note that the closure passed to ''emps.select'' can access the local variable ''threshold''. | |||
Closures can also refer to the arguments of the function in which it is defined. For example, conside the ruby code snippet below. | Closures can also refer to the arguments of the function in which it is defined. For example, conside the ruby code snippet below. | ||
<pre>def paidMore(amount) | <pre>def paidMore(amount) | ||
Line 55: | Line 56: | ||
</pre> | </pre> | ||
Note that the closure can refer to variable ''amount'' even after the function paidMore is done executing. | Note that the closure can refer to variable ''amount'' even after the function ''paidMore'' is done executing. | ||
= | === Creation Of Closures In Ruby === | ||
There are two ways to define a closure in Ruby. | There are two ways to define a closure in Ruby. | ||
* | * Using '''Proc''' | ||
* | * Using '''lambda''' | ||
The fundamental difference in the two lies in the way the return from the closure is handled. The following code snippet helps illustrates this. | The fundamental difference in the two lies in the way the return from the closure is handled. The following code snippet helps illustrates this. | ||
Line 84: | Line 85: | ||
We see that the use of ''return'' in a closure defined using '''Proc''', will return control not only from the closure but also from the enclosing function. On the other hand, the use of ''return'' in a closure defined using '''lambda''' will result in the return of control to the enclosing function. | We see that the use of ''return'' in a closure defined using '''Proc''', will return control not only from the closure but also from the enclosing function. On the other hand, the use of ''return'' in a closure defined using '''lambda''' will result in the return of control to the enclosing function. | ||
== Semantic Differences == | == Semantic Differences Between Ruby And Smalltalk Closures== | ||
This choice afforded to the programmers in Ruby is not available in all languages. For example, Smalltalk only allows the creation of closures similar to the '''Proc''' kind of closure in Ruby. For example, consider the Smalltalk code snippet below. | This choice afforded to the programmers in Ruby is not available in all languages. For example, Smalltalk only allows the creation of closures similar to the '''Proc''' kind of closure in Ruby. For example, consider the Smalltalk code snippet below. | ||
Line 109: | Line 110: | ||
The function ''foo'' seems to be defined to return a closure which in turn just returns the parameter that is passed to it. However the above code gives an error as the closure is valid only within the scope of the function in which it was defined, i.e. after ''foo'' has been called, the closure also ceases to exist. | The function ''foo'' seems to be defined to return a closure which in turn just returns the parameter that is passed to it. However the above code gives an error as the closure is valid only within the scope of the function in which it was defined, i.e. after ''foo'' has been called, the closure also ceases to exist. | ||
'''In summary, Closures in Smalltalk are essentially blocks since access to the local lexical environment is not permitted (except for local variables defined inside the block). Ruby, on the other hand, supports both blocks and true closures.''' | |||
==References== | |||
Closures (Wikipedia) [http://en.wikipedia.org/wiki/Closure_%28computer_science%29] | |||
Callback (Wikipedia) [http://en.wikipedia.org/wiki/Callback_%28computer_science%29] | |||
Closures in Ruby - Paul Cantrell [http://innig.net/software/ruby/closures-in-ruby.rb] | |||
Closures - Martin Fowler [http://martinfowler.com/bliki/Closure.html] | |||
Blocks and Closures in Ruby [http://www.artima.com/intv/closures2.html] | |||
Lecture notes provided by Dr. Gehringer on Blocks and Closures [http://courses.ncsu.edu/csc517/common/lectures/notes/lec5.pdf] |
Latest revision as of 21:45, 21 September 2007
Callbacks
A callback is code that is passed as an argument to other code. The exact behavior of a callback can be determined at runtime by passing different (yet compatible) function pointers or handles thereby uncoupling the caller from the callee. This makes callbacks easier to use than polymorphism and generic programming.
Statically scoped languages like C or C++, implement callbacks using references or pointers to code and data outside its own scope. Dynamically scoped languages (like Ruby and Smalltalk) use closures to access application data.
Closures
Closures are functions which are evaluated in an environment containing bound variables. They are blocks of code which meets three criteria:
- They can be passed around as a value.
- They can be executed on demand.
- They can refer to variables from the context in which it was created.
Closures were initally developed in the 1960s in a language called Scheme and later adopted in other languages including Ruby and Smalltalk.
Examples
The code below illustrates a simple case of closure use.
def thrice yield #Pass control back to block yield yield end x = 5 puts "value of x before: #{x}" thrice { x += 1 } puts "value of x after: #{x}"
The closure(or block) { x+=1 } is passed as a parameter to the function thrice. The value of x before thrice is called is 5. On execution the value becomes 8 i.e. the block {x+=1} was executed thrice.
Blocks are essentially chunks of code which can be passed around as arguments to functions where they can be invoked any number of times. Note that all blocks are closures, however the reverse may not always be true because closures can refer to the variables which were visible in the lexical environment of the function in which they were defined.
def highPaid(emps) threshold = 150 return emps.select {|e| e.salary > threshold} end
Note that the closure passed to emps.select can access the local variable threshold.
Closures can also refer to the arguments of the function in which it is defined. For example, conside the ruby code snippet below.
def paidMore(amount) return Proc.new {|e| e.salary > amount} end #Create new employee john = Employee.new john.salary = 200 #Call closure highPaid = paidMore(150) print highPaid.call(john)
Note that the closure can refer to variable amount even after the function paidMore is done executing.
Creation Of Closures In Ruby
There are two ways to define a closure in Ruby.
- Using Proc
- Using lambda
The fundamental difference in the two lies in the way the return from the closure is handled. The following code snippet helps illustrates this.
def foo f = Proc.new { return "return from foo from inside proc" } f.call # control leaves foo here return "return from foo" end def bar f = lambda { return "return from lambda" } f.call # control does not leave bar here return "return from bar" end puts foo # prints "return from foo from inside proc" puts bar # prints "return from bar"
We see that the use of return in a closure defined using Proc, will return control not only from the closure but also from the enclosing function. On the other hand, the use of return in a closure defined using lambda will result in the return of control to the enclosing function.
Semantic Differences Between Ruby And Smalltalk Closures
This choice afforded to the programmers in Ruby is not available in all languages. For example, Smalltalk only allows the creation of closures similar to the Proc kind of closure in Ruby. For example, consider the Smalltalk code snippet below.
foo | xs | xs := #(1 2 3 4). xs do: [:x | ^x]. ^0 bar Transcript show: (self foo) "prints 1"
Here we see that the control shifts out of foo after the first time the closure is invoked. This is because the closure is executed at the same level as the enclosing function(in this case foo).
foo ^[ x: | ^x ] bar | f | f := self foo. f value: 123 "error!"
The function foo seems to be defined to return a closure which in turn just returns the parameter that is passed to it. However the above code gives an error as the closure is valid only within the scope of the function in which it was defined, i.e. after foo has been called, the closure also ceases to exist.
In summary, Closures in Smalltalk are essentially blocks since access to the local lexical environment is not permitted (except for local variables defined inside the block). Ruby, on the other hand, supports both blocks and true closures.
References
Closures (Wikipedia) [1]
Callback (Wikipedia) [2]
Closures in Ruby - Paul Cantrell [3]
Closures - Martin Fowler [4]
Blocks and Closures in Ruby [5]
Lecture notes provided by Dr. Gehringer on Blocks and Closures [6]