CSC/ECE 517 Fall 2007/wiki1 2 pk

From Expertiza_Wiki
Revision as of 20:23, 19 September 2007 by Kkrish (talk | contribs)
Jump to navigation Jump to search

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.

IStatically 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) provide access to application data automatically via closures.

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.


However, the biggest advantage of closures is that they 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

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.

References

Closures (Wikipedia) [1]

Callback (Wikipedia) [2]

Closures in Ruby - Paul Cantrell [3]

Closures - Martin Fowler [4]