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

From Expertiza_Wiki
Jump to navigation Jump to search
 
(31 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== Callbacks ==
= Callbacks =


A callback is executable code that is passed as an argument to other code. It allows a lower-level software layer to call a subroutine (or function) defined in a higher-level layer. A callback can be used as a simpler alternative to polymorphism and generic programming, in that the exact behavior of a function can be dynamically determined by passing different (yet compatible) function pointers or handles to the lower-level function. This can be a very powerful technique for code reuse.
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.


Normally a callback uses such a parameter as a pointer to application data outside its own scope. This feature is necessary only in a statically scoped language like C or C++ . Dynamically scoped languages (like Ruby and Small Talk) can provide access to application data automatically via closures.  
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:
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 and
* 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.
Line 31: 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.  
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.  


<pre>
<pre>
Line 40: 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 54: 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.


== Semantic Differences ==
=== 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.


* Use of '''Proc'''
* Using '''Proc'''
* Use of '''lambda'''
* 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 83: 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.


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 code snippet below.
== 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>
<pre>
Line 93: Line 108:
     f value: 123 "error!"
     f value: 123 "error!"
</pre>
</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]