Changing argument inside a function using yield

Viewed 334

I am new to the concept of yield and currently practising it. I was expecting to get ["bread", "JUICY", "bread"] but I got ["bread", "steak", "bread"].

Can you please help me understand why? And how can I fix my code?

def burger(patty)
  if block_given?
    yield(patty)
  end
  return ["bread", patty, "bread"]
end


# TODO: Change 'steak'to 'JUICY'using yield
juicy_burger = burger("steak") do |patty|
  patty = "JUICY"
end
p juicy_burger
2 Answers
juicy_burger = burger("steak") do |patty|
  patty = "JUICY"
end

Reassignments like this are not propagated to the outer scopes. Once this block returns, patty "reverts" to its initial value.

Solution? Use the overwritten value while it's still in scope.

def burger(patty)
  if block_given?
    patty = yield(patty)
    # ^ shadow the parameter here. 
    # doesn't have to be a shadow. You can use any name. new_patty = yield(patty)
  end
  return ["bread", patty, "bread"]
end


juicy_burger = burger("steak") do |patty|
  "JUICY #{patty}" # <- simple return here
end
p juicy_burger # >> ["bread", "JUICY steak", "bread"]

The variable is local to the function and you did not save back the value yield returned. The code below will give you ["bread", "JUICY", "bread"]

def burger(patty)
  if block_given?
    patty = yield(patty) # <-- this is the diff
  end
  return ["bread", patty, "bread"]
end


# TODO: Change 'steak'to 'JUICY'using yield
juicy_burger = burger("steak") do |patty|
  patty = "JUICY"
end
p juicy_burger
Related