This forum is now read-only. Please use our new forums! Go to forums

0 points
Submitted by Anu
almost 11 years

I don't really understand what is this yield

I got the exercise correctly and my code is as below

def double(n)
yield n

end

double(2) do |n|
n*=2
end

But my question is I don’t really understand why need to do like this when there is a more easier way like the following

def double(n)
n*=2

end

double(2)

Can anyone explain why do we need to use yield?

Answer 51c75f68631fe903b4001e5d

215 votes

Permalink

In the very simple example you presented, yield doesn’t make much sense indeed. But the mechanism of yielding to blocks in Ruby provides the programmer with a great flexibility. A block is simply a chunk of code, and yield allows you to “inject” that code at some place into a function. So if you want your function to work in a slightly different way, you don’t have to write a new function, instead you can reuse the one you already have, but give it a different block.

For example, consider a function that will print the members of an Array, but number them, like this: if you give it ["apple","banana"], it should print

1. apple
2. banana

Easy enough, right? There are several ways to do this, but I’ll just use each and a counter. Instead of incrementing the counter via += 1, I’d like to use the next method (you’ll see why in a moment). Here’s how the next method works: 3.next equals 4, 99.next is 100 and so on. So here’s our method (without yield):

def print_list(array, first = 1)
  counter = first
  array.each do |item|
    puts "#{counter}. #{item}"
    counter = counter.next
  end
end

Now when we call print_list(["Ruby", "Python", "C"]), it’ll print

1. Ruby
2. Python
3. C

The second parameter first is optional (it defaults to 1 because of the first=1 above) and it tells our function where to start counting:

print_list(["a","b","c"], 99)

will print

99. a
100. b
101. c

Because I chose next over += 1 to increment the counter, and because Ruby is really awesome, we can use strings instead of numbers to label the list items: "A".next is "B", and so forth. Thus

print_list(["Ruby", "Python", "C"], "X")

# will print:

X. Ruby
Y. Python
Z. C

Great, right? But what if we wanted a different format for the item labels? Say, (1), (2), (3) instead of 1., 2., 3.? Our function does the formatting in this line:

puts "#{counter}. #{item}"

So instead of having two (almost identical) functions – one for 1. 2. and one for (1) (2) (and so on, one for every possible idea), we’re going to export that formatting thing into a block, and have just a yield inside the function:

# function print_list, line 4:
puts "#{yield counter} #{item}"

Now we can have a block handle the formatting:

print_list( [1,2,3], 23 ) { |n| "<#{n}>"}

# produces: 

<23> 1
<24> 2
<25> 3

Now I hope you see how this yield adds flexibility to your method. You can, for instance, have something like this:

print_list( ["alpha","beta","gamma"], 5 ) do |n|
  "[#{100*n}]:"
end

This prints… can you guess what it prints? Try to figure it out, then go here to find out the answer and see more examples.

points
Submitted by Alex J
almost 11 years

29 comments

Anu almost 11 years

Thanks a lot Alex. I got how yield works from your explanation. Though I didn’t understand some of the codes you given for the different printing formats.

I don’t understand this part:

function print_list, line 4:

puts “#{yield counter} #{item}”

I do understand what the “yield” does in there, but where did the # function print_list, line 4:” come from? Very confused

Alex J over 10 years

It’s simply the fourth line in the function I defined above… Just replace the fragment puts "#{counter}. #{item}" with the fragment puts "#{yield counter} #{item}" inside the definition of the print_list function.

thank you :)

Alex J over 10 years

see my answer below

Brian W over 10 years

I would just like to say that if an example “doesn’t make much sense” as you point out, it’s probably not a good idea to use it to introduce new concepts in a beginner’s tutorial.

Snarik over 10 years

Holy shit that was a great explanation. I wish I could mail you a medal or at least a cuddle or something.

Anna Baik over 10 years

Thank you! This is great :)

alibedde about 10 years

Great explanation! Thanks a lot!

Danny Sullivan about 10 years

Thank you for this explanation. For me, a lot of these exercises lack context, it is hard to see exactly how and why you would use whatever it is you are learning. Your explanation cleared that up in the first two sentences. I wish Codecademy would start to incorporate more examples of why you would use something instead of just giving an exercise.

Oleg Joel Malinovsky almost 10 years

Oooohh… this this is what it does. THANKS!

znapper almost 10 years

Thanks Alex!! Great Explanation!

Kyler Chua almost 10 years

Thank you Danny for raising the question. Was lost as well. Alex thank you for spending time explaining, appreciate it! XD

Anne N almost 10 years

Thank you so much for explaining this! I was so confused as to how yield was applicable when other methods work just as well for this particular assignment. Much appreciated!

Alex almost 10 years

Thank you!!

Mantas Jonušas over 9 years

good explanation. but why don’t do formating in the puts line: puts “<#{counter}> #{item}” and etc. and do things as simple as possible

Thank you much!!

Todd Mathews over 9 years

Very good explanation. Thanks I understand it now.

Bekah over 9 years

THANK YOU.

bumblebeezel over 9 years

Godsend

Toby over 9 years

Useful, nice to have a concrete example of why we might do something, instead of just how.

Leah Suter over 9 years

Yeah I agree with Toby. Thank you both.

NYJY85 over 9 years

Thank you for the explanation! But I am wondering how does ruby know that ‘n’ refers to the second parameter and not the first in ‘print_list( [1,2,3], 23 ) { |n| “<#{n}>”}’

Ti Pro almost 9 years

I think because n is a number, a symbol not is an array. Beside that, yield make you have a prametter so ruby will follow this parameter to do with block

Jenn Goble over 8 years

Thanks for such a helpful explanation!

Spencer Romberg over 8 years

Well done. Have you ever considered going into computer science for teaching?

Michael Du over 8 years

I know this post is 2 years old, but hoping you’re still around for questions: Why do we need “counter” in your example? It works perfectly fine using “first” directly within the block.

Nitya Narayan over 8 years

to retain value of first.counter value is incremented…. ‘first’ value remains the same

BlackFiresong over 8 years

Amazing! Thank you so much. I was really mystified by the whole yield thing. Thanks for taking the time to write such a detailed explanation. If you’re not a teacher by profession, you should be!

Answer 51caff9352f8633982007a5c

0 votes

Permalink

this explanation also helped em alot understand the yield thingy. thanks a lot @Alex

points
Submitted by siaw23™
almost 11 years

1 comments

Alex J almost 11 years

Glad I could help

Answer 53c9cd74631fe9afa9000054

0 votes

Permalink

Great explanation, thanks

points
Submitted by Ray Rai
over 9 years