3

I have a list:

list = ["mango", "apple", "pearl", "peach"]

and I need to use yield so that this line of code:

answer = myIndexOf(list) {|e| e == "apple"}

returns the value 1, which is the index of "apple" in the array.

I have this, but I don't understand yield.

def myIndexOf(list)  
  yield answer if block_given?  
  result = list.index(answer)  
  return answer  
end  

Can anyone shed some light on this?

sawa
  • 165,429
  • 45
  • 277
  • 381
fwefwf
  • 141
  • 5
  • Yes, I don't get yield at all. all the examples did not make any sense. – fwefwf Jul 29 '17 at 21:38
  • `yield` means 'give control to the block. `yield(e)` or `yield e` mean give control to the block passing `e` to the block variable. In English 'yield' can mean to 'give up' or 'hand over'. So if you yield control, you hand over control. Same kinda meaning in programming. Just keep working at it. I think the above question is a bit tricksy, but follow Sergio's advice and it may click. – Sagar Pandya Jul 29 '17 at 23:50
  • What is the local variable `answer` in the method body? – sawa Jul 30 '17 at 10:45
  • Possible duplicate of [Blocks and yields in Ruby](https://stackoverflow.com/questions/3066703/blocks-and-yields-in-ruby) – Charles Aug 29 '17 at 14:43

3 Answers3

7

Understanding yield/blocks is actually quite simple. Just think of blocks as methods and yield as a way of calling those methods.

Imagine that, instead of block, you have this

def is_this_the_right_item?(item)
  item == "apple"
end

def myIndexOf(a_list)
  # your implementation goes here
end

answer = myIndexOf(list)

Can you code this implementation of myIndexOf? It doesn't involve yielding at all. And when you're done, you simply bring the block back to the invocation of myIndexOf and replace all calls to is_this_the_right_item? with yield.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • 7
    Obviously, I could have just pasted fixed code. But where's the learning in that? – Sergio Tulentsev Jul 29 '17 at 21:43
  • Yeah I still don't get it. – fwefwf Jul 31 '17 at 21:45
  • @fwefwf Have you followed my hint and implemented alternate implementation of `myIndexOf`? – Sergio Tulentsev Jul 31 '17 at 21:47
  • No it doesn't make any sense to me how you can do it myIndexOf only takes in the list, but the user doesn't provide what element he wants I don't know how to extract because in other languages its jsut given. – fwefwf Jul 31 '17 at 21:57
  • @fwefwf: `is_this_the_right_item?` method knows which element the user wants. You pass it an element, it returns true or false. `myIndexOf` should use that method to determine which element to return. Oh, and don't use `a_list.index()`. You're trying to reimplement `index`, aren't you? So using the original implementation kinda defeats the purpose. – Sergio Tulentsev Jul 31 '17 at 22:00
  • No I can use the index method I just need to use the world yield. thats the only requirement – fwefwf Jul 31 '17 at 22:03
  • @fwefwf: but you don't _have_ to use it? Because without it, it'll be much simpler. Perhaps, this is too complex for now and you should try simpler examples? Would you be able to implement this `myIndexOf` in, say, javascript or another language? – Sergio Tulentsev Jul 31 '17 at 22:07
  • I honestly think I can put it together if I just saw how it would look with the index method. I can easily make the index method I just don't understand how passing in a block like {|e| e == "apple"} translates to a variable in the method. – fwefwf Jul 31 '17 at 22:09
  • @fwefwf: and yet again I suggest you try my exercise. At this level, calling a block is very much like calling a method. – Sergio Tulentsev Jul 31 '17 at 22:11
2

yield calls the block.

The following functions are "the same"

def example()
  raise unless block_given?
  yield 1
  yield 2
  yield 3
end

def example(&block)
  block.call(1)
  block.call(2)
  block.call(3)
end

Both can be called as follow

example { |each| puts each }

Both will then output

1
2
3

Hope that helps to shed light on higher-order functions in Ruby.

akuhn
  • 27,477
  • 2
  • 76
  • 91
0

Further to Sergio's answer:

list = ["mango", "apple", "pearl", "peach"]

def myIndexOf(a_list)
  a_list.index { |e| yield e }
end

p answer = myIndexOf(list) { |e| e ==  'apple' }
#=> 1

I'm submitting because I thought this was a tricky exercise and reverse engineering the answer may help you.

Sagar Pandya
  • 9,323
  • 2
  • 24
  • 35