CSC/ECE 517 Fall 2007/wiki1 2 pk: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
 
(47 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 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 usually found in languages which treat functions as first class values i.e. they can passed around as arguments to functions, bound to variables and even be returned from functions. Closures were initally developed in the 1960s in a language called Scheme and was later adopted in other languages including Ruby and Smalltalk.
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.
 
<pre>def thrice
    yield #Pass control back to block
    yield
    yield
end


Assume, we have list of employees and we want to find the list of employees who are managers. The following ruby code shows how this can be done with closures.


<pre>def managers(emps)
x = 5
  return emps.select {|e| e.isManager}
puts "value of x before: #{x}"
end</pre>
thrice { x += 1 }
puts "value of x after: #{x}"</pre>


However, the biggest advantage of closures is that they can refer to the variables which were visible at the time they were defined. An small example using closures is shown below, where we pick the employees who have a salary greater than a thershold.
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 15: Line 39:
   return emps.select {|e| e.salary > threshold}
   return emps.select {|e| e.salary > threshold}
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.
<pre>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)
</pre>
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.
<pre>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"
</pre>
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.
<pre>
  foo
    | xs |
    xs := #(1 2 3 4).
    xs do: [:x | ^x].
    ^0
  bar
    Transcript show: (self foo) "prints 1"
</pre>
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'').
<pre>
foo
    ^[ x: | ^x ]
  bar
    | f |
    f := self foo.
    f value: 123 "error!"
</pre>
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]