What is a block in ruby. A block is a piece of code. However a block has to be attached to something.
1.# this wont' work2.{ |x| puts x }3. 4.# this won't work either5.temp_block = {|x| puts x }So how do I carry a piece of code from one place to another. Convert that piece of code into a proc.
1.temp_proc = Proc.new { puts "inside a block" }2.temp_proc.call # inside a blockWhat is temp_proc here. Let’s find out the class of temp_proc.
1.temp_proc = Proc.new { puts "inside a block" }2.puts temp_proc.class.to_s # ProcWhat is lamda. Lamda is another way to convert a block of code into a proc.
1.temp_lambda = lambda { puts "inside a block" }2.temp_lambda.call # inside a blockLet’s see what is the class of the temp_lambda.
1.temp_lambda = lambda { puts "inside a block" }2.puts temp_lambda.class.to_s # Proctemp_lambda is a Proc. It means both lambda and Proc.new create an instance of “Proc”. Then what’s the different between the two.
Differences between lambda and Proc. I know of two distinctions.
01.temp_proc = Proc.new {|a,b| puts "sum is #{a + b}" }02.temp_lambda = lambda {|a,b| puts "sum is #{a + b}" }03. 04.temp_lambda.call(2,3) #505.temp_lambda.call(2) #wrong number of arguments error06.temp_lambda.call(2,3,4) #wrong number of arguments error07. 08.temp_proc.call (2,3) # 509.temp_proc.call (2) 10.# nil can't be coerced. Since the second parameter was not supplied, 11.# proc.call supplied nil for the missing parameter12.temp_proc.call(2,3,4) #5First difference is that lambda.call wants the exact number of parameters to be supplied. Otherwise lambda will throw “wrong number of arguments error”. While Proc doesn’t demand that. For the missing params proc will supply “nil” and any extra parameter is ignored.
01.def learning_proc02. temp_proc = Proc.new { return "creating proc" }03. temp_proc.call # control leaves the method here04. return "inside method learning_proc"05.end06. 07.puts learning_proc08. 09.def learning_lambda10. temp_lambda = lambda { return "creating lambda" }11. temp_lambda.call # control doesn't leave the method here12. return "inside method learning_lambda"13.end14. 15.puts learning_lambdaSecond difference has to do with the usage of the word “return” in the context of proc. When there is a return keyword inside the block then proc treats that statement as returning from the method. Hence the statement return “inside method learning_proc” was never executed. Lambda behaves the way ruby behaves in general. The control goes to the next statement after the temp_lambda.call is finished.
The point to be noted is that not all the temp_proc.call will ensure the return from the method at that very instant. It’s the usage of the word return that is causing this behavior. This code will work just fine.
1.def learning_proc2. temp_proc = Proc.new { "creating proc" }3. temp_proc.call 4. return "inside method learning_proc"5.end6. 7.puts learning_procIn ruby any method can accept a block and the methods do not need to do anything to accept this block of code. All the method has to do is to call “yield” and the piece of code will be invoked.
01.def learning02. puts "learning ruby "03. yield04. puts "learning rake"05.end06. 07.learning {puts "learning rake" }08. 09.# output is10.#learning ruby 11.#learning rake12.#learning rakeIn the above example method “learning” did not have to do anything to accept the block. This feature is built into ruby.
However if the method wants to detect if a block is being passed to it or not, it can use the method block_given?.
01.def learning02. puts "learning ruby "03. 04. if block_given?05. yield06. else07. puts "no block was passed"08. end09. puts "learning rake"10.end11. 12.learning 13. 14.# output is15.#learning ruby 16.#no block was passed17.#learning rakeThere is another way to pass a block to a method: as an argument. However this argument must be the very last argument. It works like this.
1.def learning(&block)2. block.call3.end4. 5.learning { puts "learning" }In the above case there is an ampersand sign before the name “block”. That ampersand sign is important. By using that sign we are telling ruby that a block is being passed and convert that block into a proc and then set the variable name of the block as “block”. Now we can invoke “block.call”.
We can pass variables to a block. However it is important to understand the scope of the variable. Try this.
01.def thrice02. x = 10003. yield04. yield05. yield06. puts "value of x inside method is #{x}"07.end08. 09.x = 510.puts "value of x before: #{x}"11.thrice { x += 1 }12.puts "value of x after: #{x}"13. 14.#output15.#value of x before: 516.#value of x inside method is 10017.#value of x after: 8This is something. A block will not touch variables defined inside the method. What happens if outer x is not defined.
01.def thrice02. x = 10003. yield04. yield05. yield06. puts "value of x inside method is #{x}"07.end08. 09.puts "value of x before: #{x}"10.thrice { x += 1 }11.puts "value of x after: #{x}"12. 13.#output14.#undefined local variable or method `x' for main:Object (NameError)Hopefully this provides some idea about blocks, procs and lambda. I intend to add some more cases later to this article.
1 Comments
Its a hilarious site. I have learned so many from here and I love the person who written this...
ReplyDelete