CSC/ECE 517 Fall 2012/ch1b 1w60 ac: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 104: Line 104:
</pre>
</pre>
In this example, the yield function is used to allow the tree owner to do whatever they want to each element of a tree. This example just prints the name of each node of the tree, but passing a more complex code block would let you do whatever you like with each child.
In this example, the yield function is used to allow the tree owner to do whatever they want to each element of a tree. This example just prints the name of each node of the tree, but passing a more complex code block would let you do whatever you like with each child.
In this example, we create a class that includes Enumerable, providing access to the <code>each</code> method, among others. So, when
In this example, we create a class that includes Enumerable, providing access to the <code>each</code> method, among others.
===Random Sequence===
<ref>http://pastebin.com/T3JhV7Bk</ref>
<pre>
class RandomSequence
  def initialize(limit,num)
    @limit,@num = limit,num
  end
  def each
    @num.times { yield (rand * @limit).floor }
  end
end
 
i = -1
RandomSequence.new(10,4).each do |num|
  i = num if i < num
</pre>
This example comes from the SaaS video on the Ruby <code>yield</code> statement.
In this example, the yield statement is used to execute the user defined code block for each random number the class generates. Each time <code>each</code> yields to the code block, <code>i</code> will be updated if the parameter to <code>yield</code> is the smallest value thus far. This is a great example of how passing a parameter to the <code>yield</code> function allows for concise code.
==Further Readings==
==Further Readings==
==References==
==References==
<references/>
<references/>

Revision as of 03:51, 3 October 2012

SaaS - 3.8 yield()

Introduction (Preface)

In order to properly understand and cover the idea of how the Ruby yield function works, it is necessary to understand a few concepts that do not exist in other object oriented languages.

Code Blocks & Closures

Unlike Java (and several other object oriented languages) you can not only pass values and references, but you can also pass blocks of code as parameters in Ruby. A block of code that is both passable and can maintain all variables in it’s original scope, is called a closure. Here is an example of using a code block:

codeblock = {puts "foo"}
codeblock.call

Executing this code will print:

foo

This is a very simple example, but it shows how code blocks can be defined, stored into a variable and called later. This is very important to understanding what the yield function does.

An unbound closure, meaning the body of a closure itself, is referred to as a code block. A code block gives a shortcut, without explicitly creating an object, to pass around a block of code to be executed. This enables a programmer to quickly pass a block of code that they might want to implement across several objects or at several points of another function.

The Map & Grep Functions

A great example of code blocks being used is in the map and grep functions. The Map function allows you to apply a function to every element of a list or collection, independent of the collection's type. A new collection is created based on the execution of the block on every element. An example would be:

# This code example subtracts 2 from every element of the list
mylist = mylist.map{|x| x-2}

The Grep function allows you to search a collection for all elements that match a given criteria. Then a new collection is returned containing only those elements that match. An example would be.

# This code example returns all elements less than 5
arr = arr.grep(|x| x<5) 

The way in which these two functions work depends on being able to run a block of code across several objects without ever examining the objects themselves. In Ruby, rather than iterating through a series of elements and calling an operation on them, we can pass a code block as an argument to a function that will then perform that code block whenever the correct conditions are satisfied.

The yield() Function

What Is It?

Simply put, the yield function in Ruby passes control to a user-defined code block. As simple as that statement is, it can be quite confusing, so here is a quick example<ref>http://www.tutorialspoint.com/ruby/ruby_blocks.htm</ref>:

def test
   puts "You are in the method"
   yield
   puts "You are again back to the method"
   yield
end
test {puts "You are in the block"}

Executing this code results in:

You are in the method
You are in the block
You are again back to the method
You are in the block

First, take a look at the last line of code. You'll notice that the parameter to the test function is actually a code block. Next, look at where the text "You are in the block" appears: after the "You are in the method" text then again after the "You are again back to the method" text. Notice how this corresponds to where the yield statements are in the code? That's because the yield statement is calling the code block, then returning control to the test method.

Syntax

As you may have guessed from the previous example, the yield function's syntax is quite simple. In it's most basic form, the yield function can be called with:

yield

In this form, the yield function will simply execute the code block passed to the function it's called from. You can also pass parameters to the yield function which passes those parameters to the code block, like so:

yield parameter

Passing parameters allows you to call the same code block, but with different input. For example<ref>http://www.tutorialspoint.com/ruby/ruby_blocks.htm</ref>:

def test
   yield 5
   puts "You are in the method test"
   yield 100
end
test {|i| puts "You are in the block #{i}"}

Executing this code results in:

You are in the block 5
You are in the method test
You are in the block 100

See how the same code block results in different output yielded to the first and second times? That's because the values 5 and 10 are passed each time, respectively, and output by the code block.

Why It's Useful

Examples

Tree Traversal

<ref>https://docs.google.com/viewer?url=http%3A%2F%2Fcourses.ncsu.edu%2Fcsc517%2Fcommon%2Fhomework%2Ftests%2Fa1.pdf</ref>

class Tree
  attr_reader :value
  def initialize(value)
    @value = value
    @children = []
  end
  
  def <<(value)
    subtree = Tree.new(value)
    @children << subtree
    return subtree
  end
  
  def each
    yield value
    @children.each do |child_node|
      child_node.each { |e| yield e }
    end
  end
end

t = Tree.new()
... # code to populate the tree
t.each {|x| puts x}

In this example, the yield function is used to allow the tree owner to do whatever they want to each element of a tree. This example just prints the name of each node of the tree, but passing a more complex code block would let you do whatever you like with each child. In this example, we create a class that includes Enumerable, providing access to the each method, among others.

Random Sequence

<ref>http://pastebin.com/T3JhV7Bk</ref>

class RandomSequence
  def initialize(limit,num)
    @limit,@num = limit,num
  end
  def each
    @num.times { yield (rand * @limit).floor }
  end
end

i = -1
RandomSequence.new(10,4).each do |num|
  i = num if i < num

This example comes from the SaaS video on the Ruby yield statement. In this example, the yield statement is used to execute the user defined code block for each random number the class generates. Each time each yields to the code block, i will be updated if the parameter to yield is the smallest value thus far. This is a great example of how passing a parameter to the yield function allows for concise code.

Further Readings

References

<references/>