Collections,

Iterators & Closures

in Ruby

Contents

  • Collections
  • Conditional statements
  • Loops
  • Iterators
  • Closures

Collections

  • Array
  • Hash

Conditional Statements

  • If else
  • unless
  • case

Loops

(Don't Use)

  •  while
  • until
  • for
  • break
  • next
  • retry

Iterators

  • each
  • times
  • collect = map
  • select
  • reject
  • detect = find (first)
  • inject = reduce
  • delete_if
  • keep_if
     etc...

Closure

a persistent local variable scope which holds on to local variables even after the code execution has moved out of that block.

function makeCounter () {
  var count = 0;
  return function () {
    count += 1;
    return count;
  }
}

var x = makeCounter();

x(); returns 1

x(); returns 2

Blocks

A block is code that is implicitly passed to a method
Convention: use {...} for single line blocks, and do...
end for multi-line blocks.

array = [1,2,3,4] 
array.map! do |n|
  n * n 
end
=> [1, 4, 9, 16]

array = [1,2,3,4] 
array.map! { |n| n * n } 
=> [1, 4, 9, 16]

Using Blocks & yield

yield: It defers the execution of the method in order to evaluate the block.
The yield statement can also accept parameters, which are then passed into and evaluated within the block.
 

class Array 
  def map
    self.each_with_index do |value, index| 
      self[index] = yield(value)
    end 
  end
end

Procs

 

  • We have to retype blocks every time we reuse them on different arrays
  • We can store a block for later use by using the Ruby Proc Object.
  • We can store a Proc in a variable, and then explicitly pass it to any method that accepts a callable object.
#pass it to any method that accepts a callable object.
class Array
  def map!(proc_object) 
    self.each_with_index do |value, index|
      self[index] = proc_object.call(value) 
    end
  end
end 

Procs...

number_squared = Proc.new { |n| n * n } 
array = [1,2,3,4] 
array.map!(number_squared)
=> [1, 4, 9, 16]

*Note: We no longer use the yield keyword; instead, we directly use the call method on the Proc object, passing it the value from the array.

Lambda

lambo = lambda { "I'm a lambda" } 
lambo.call
=> "I'm a lambda" 
lambo.call('arg')
ArgumentError: wrong number of arguments (1 for 0)

Lambda function are almost identical to Procs but with two key differences.

  1. A lambda checks the the number of arguments it receives and returns an ArgumentError if they do not match.

  2. Lambdas provide diminutive returns – meaning that when a Proc encounters a return statement in it’s execution, it halts the method and returns the provided value. Lambdas on the other hand, return their value to the method, allowing it to continue

Lambda...

def proc_math
  Proc.new { return 1 + 1 }.call 
  return 2 + 2
end
def lambda_math
  lambda { return 1 + 1 }.call 
  return 2 + 2
end
proc_math # => 2 
lambda_math # => 4

Conclusion

In this study, we've covered the key differences between Blocks, Procs, and Lambdas

  1. Blocks are single use.
  2. Procs exist as objects.
  3. Lambdas have strict argument checking and provide diminutive returns.

Questions?

References

  • https://docs.ruby-lang.org/en/2.4.0/Array.html
  • https://docs.ruby-lang.org/en/2.4.0/Hash.html
  • http://stackoverflow.com/questions/36636/what-is-a-closure
  • http://www.elonflegenheimer.com/2012/07/08/understanding-ruby-closures.html
  • https://scotch.io/tutorials/understanding-ruby-closures

Thank You

Made with Slides.com