CSC/ECE 517 Fall 2012/ch1 1w31 sa: Difference between revisions
No edit summary |
|||
Line 192: | Line 192: | ||
=='''References'''== | =='''References'''== | ||
<references/> | |||
=='''Further Suggested Reading'''== | =='''Further Suggested Reading'''== |
Revision as of 05:40, 13 September 2012
Closures and Methods:
Introduction
This article helps in understanding the concepts of Closures and Methods and also provides a comparison between the two.
In Statically typed languages, methods (also known as procedures or functions) are a set of instructions that perform a specific task. The main objective of methods is to provide reusability of code. Methods can be used to retrieve the state of an object i.e. object’s instance variables. Existence for methods is tied to life time of Objects to which they belong. But many a times there are certain problem domains, where methods are not enough to provide a flexible, elegant implementation and we need the state of a variable to persist even when it is not in the scope of currently running method. One such elegant mechanism which comes out handy in situations as such is Closure.
Closures are blocks of code that can be passed around like objects, which have the property that they are "bound" to the context (or state of the program) in which they were created and therefore are not dependent on the presence of object or functions which created it.
Methods
A Method is a Subroutine (or Procedure or Function) in a class that defines the behaviour exhibited by the associated Class instances at runtime. Methods defined within a Class are bound to the class either by Static binding or Dynamic binding.
Following is a Ruby example that shows how methods can be used to statically bind to the state of an object:
class Account def initialize(default) @balance = default end def get_balance @balance end def set_balance(value) @balance = value end end account1 = Account.new(100) puts account1.get_balance #prints 100 account1.set_balance(200) puts account1.get_balance #prints 200
Here the methods are statically bound to the object account1 and have access to its state as long as this object is in existence.
Different types of methods
Instance methods
Instance methods are the methods which are bound to objects of the class i.e. there creation depends on creation of object. Instance methods can access instance variables and instance methods directly. Instance methods can also access class variables and class methods directly.
Static methods
These are also known as Class methods as they belong to the whole class and not a instances or objects in the class. We need these methods if we don’t want a particular functionality to be dependent on creation of objects. Class methods can access class variables and class methods directly. Class methods cannot access instance variables or instance methods directly i.e. they must use an object reference. Also, class methods cannot use this keyword as there is no instance for this to refer to.
For Example: In Java we have a method public static void main(Strings args[]). This method is where the interpreter starts reading the code and this is a static method because this is the first method that is called when we try to execute the class and at that time there are no objects created.
Accessor methods
Accessor methods are a instance method with the aim to get or set the value of instance variables. Object oriented languages provide the way to hide the instance variables associated with object to outside world by means of encapsulation i.e. marking the instance variables private. So any object can’t access the instance variables of a class directly, this is where accessor methods come into picture. They are the methods through which an object can access the instance variables and we can define some rules in these methods which should be fulfilled in order to set or get these variables.
Example: In following Java class weight is an instance variable and is marked private so that any object can’t directly set its value to some incorrect state. Like weight can’t be negative.
Class Person { private int weight; public int getWeight() { } public int setWeight(weight) { if(weight < 0) { // Some error } else { this.weight = weight; } } }
Closures<ref>http://www.skorks.com/2010/05/closures-a-simple-explanation-using-ruby/</ref>
A closure is a computer science concept which can be seen in different web programming languages such as JavaScript, Ruby, ActionScript 3.0 and newer versions of PHP.
A closure is basically a method/function that has the following two properties:
- We can pass it around like an object (to be called later)
- It remembers the values of all the variables that were in scope when the function was created. It is then able to access those variables when it is called even though they may no longer be in scope.
Closures must be explicitly supported by the language. In order for the language to be able to support closures, it must support first-class functions.
Comparison with methods
A normal function is defined in a particular scope (i.e. in a class) and can only be called within that scope. This function has access to all the variables in the scope that it is defined, like the parameters that are passed into it as well as class variables.
A closure on the other hand may be defined in one scope and be called in a completely different scope (since we can pass it around before calling it). Because of this, when a closure is created, it retains the values of all the variables that were in scope when the closure was defined. Even if the variables are generally no longer in scope when the closure is called, within the closure they still are. In other words, the closure retains knowledge of its lexical environment at the time it was defined.
Examples
A Simple Example of a Closure
4.times {puts "Inside the times method."} Output: Inside the times method. Inside the times method. Inside the times method. Inside the times method.
Here, times is a method on the 4 object. It executes the code in the closure four times. {puts "Inside the times method."} is the closure. It is an anonymous function that is passed into the times method and prints a static sentence. This code is simpler than the alternative with a for loop, shown in the next example.
Looping without closures
for i in 1..4 puts "Inside the times method." end
Argument list is the first extension that Ruby adds to the simple code block . A method or function can communicate with a closure by passing in arguments. In Ruby, we represent the arguments with a comma-separated list of arguments, between ||characters, such as |argument, list|. Using arguments in this way, we can easily build iteration into data structures such as arrays.
Using closures with collections
['red', 'green', 'blues'].each {|item| puts item} Output: red green blue
The each method is just one way to iterate. Often, we want to produce a new collection with the results of an operation. This method in Ruby is called collect. We may also join the contents of an array with some arbitrary string, which is shown in the next example.
Passing arguments to a closure
colours = ['red', 'green', 'blue'].collect {|item| item.upcase} puts colours.join(" and ") + " nothing." RED and GREEN and BLUE and nothing.
Here, the first line of code takes each element of an array, calls the closure on it, and then builds a collection with the results. The second concatenates all of the elements into a sentence, with " and " between each one.
Advantages of Closures
Closures are very useful for making code more clear and readable, which eventually is easier to debug and contains fewer bugs. Closures are extremely useful for implementing call-backs in event driven systems. Closures can be used to define control structures. Designers of software libraries can allow users to customize behaviour by passing closures as arguments to important functions. For example, a multiple generator function can generate any multiple as required by user for a number as shown below:
def create_multiplier lambda do |n| n *m end end doubler = create_multiplier(2) tripler = create_multiplier(3) quad = create_multiplier(4) puts doubler[5] # 10 puts tripler[10] # 30 puts quad[15] # 60
Blocks
Blocks are the most commonly used form of closures in Ruby. We can find them all over the core Ruby libraries. They are nameless functions and can be passed anywhere. Blocks can be visualized as just a chunk of code that will be yielded to or called in the method we supply it to. Blocks are defined after the last parameter to a method call between {} or do/end. Each call to yield in the method will invoke the block that was passed to that method. We can specify arguments to yield that will be passed to the block. If we do this, we must also specify the same parameters in the block definition. Each method can only receive a single block argument; although, it may yield to this single block multiple times. Calling yield without supplying a block will result in an error.
A simple example:
arr = [1,2,3,4] arr.each do |bl| puts bl end Output: 1 2 3 4
Procs
Procs are nameless block of code that can be represented as an object and can be passed around or called at will. A Proc is a closure and an object that can be bound to a variable and reused. Procs are defined by calling Proc.new or proc followed by a block. It can also be created by calling the #to_proc method of a Method, Proc, or Symbol. A Proc can be invoked through its #call method.
p = Proc.new do puts 'Hello!' end p.call p.call p.call Output: Hello! Hello! Hello!
We created a proc which held the block of code, and then we called the proc three times.
The main difference between a block and a proc is that, we can only pass a single block to a method but we can pass multiple procs around because procs are regular objects.
Lambdas
Lambdas are a more strict form of Proc. They are defined with lambda or ->(). The differences between a lambda and a proc are:
- Lambdas are more strict with regard to argument checking.
- Lambdas can return a value with the return keyword.
1 a = ->(x,y) {x+y} 2 a.call 2,3 3 => 5
Conclusion
Closures are more convenient to use than traditional methods and they provide better encapsulation of private information. This doesn't necessarily mean that closures should be added to languages that don't fully support them. However there is a good place for them in dynamic languages such as Ruby and JavaScript, as well extensions of static languages such as Groovy.
References
<references/>