Yield vs. return

I couldn’t find any meaty discussions on this topic, so maybe it’s
worth a post.

Does it make sense to use yield at the end of a function, where you’re
essentially
using yield to replace a return value? For example:

def returnfoo
return foo
end

vs.

def yieldfoo
yield foo
end

I see a lot of ruby programmers doing the latter, but consider the
former to
be more straightforward. There are a lot of cases where yielding is
more elegant
than return, but I don’t consider this to be one of them. Anyone care
to weigh in?

Alle mercoledì 28 gennaio 2009, klochner ha scritto:

than return, but I don’t consider this to be one of them. Anyone care
to weigh in?

yield and return do completely different things, and you can’t use one
in
place of the other. return tells ruby to stop executing the method and
return
its argument to the caller. yield tells ruby to call the block passed to
the
method, giving it its argument. yield will produce an error if the
method
wasn’t called with a block:

def test_yield
yield 43
end
test_yield # notice that no block was passed to the method
=> LocalJumpError: no block given

In ruby, there’s no need to put a return at the end of a method, as the
method
will always return the value of the last expression. This means that a
method
defined this way:

def test_return
return 4
end

will give exactly the same result as a method defined this way:

def test_no_return
4
end

Can you give an example of a situation where you think yield is used in
place
of return? This way, we’ll be able to understand better what you’re
referring
to and make more useful comments.

Stefano

On Jan 28, 3:21 pm, Stefano C. <stefano.cro…@ali

Can you give an example of a situation where you think yield is used in place
of return? This way, we’ll be able to understand better what you’re referring
to and make more useful comments.

Stefano

The calling code would need to be modified to work with yield vs.
return.

Here’s a slightly different example, because I see this a lot with
multivariate return values:

##return style, with calling code below
def returnfoo
return foo1,foo2
end
a,b = returnfoo
puts a; puts b

vs.

##yield style, with calling code below
def yieldfoo
yield foo1, foo2
end
yieldfoo {|a,b| puts a; puts b }

What I’m getting at is that I see ruby programmers use yield to
essentially return values to the caller, the distinction being whether
the block is executed by the caller or by the method (returnfoo/
yieldfoo). It could be done either way because no operations are
performed by the method after the yield.

Le 28 janvier 2009 à 21:09, klochner a écrit :

I see a lot of ruby programmers doing the latter, but consider the
former to be more straightforward. There are a lot of cases where
yielding is more elegant than return, but I don’t consider this to
be one of them. Anyone care to weigh in?

Depends on what you do with it. I kinda like to use yield in “builder”
statements where the code will we nested.

For instance, something like (completely random example) :

box.contents do |c|
c.title = “Blah”
c.font = “Courier”
c.color = “Blue”
c.para do |t|
t.text = “This is blahblah”
t.color = “Black”
end
end

While you could do something like :

c = box.contents
c.title = “Blah”
c.font = “Courier”
c.color = “Blue”
t = c.para
t.text = “This is blahblah”
t.color = “Black”

(The code behind the ‘para’ method would probably just be ‘yield @para
or ‘yield Para.new(self)’.)

The best (IMHO) is, of course, the freedom of :

def funcfoo
yield foo if block_given?
foo
end

Where you can nest or assign.

Fred

On Jan 28, 4:04 pm, “F. Senault” [email protected] wrote:

The best (IMHO) is, of course, the freedom of :

def funcfoo
yield foo if block_given?
foo
end

thanks Fred, this sounds sane to me.

2009/1/28 klochner [email protected]

vs.
the block is executed by the caller or by the method (returnfoo/
yieldfoo). It could be done either way because no operations are
performed by the method after the yield.

IMHO that would be a bad use case for /yield/. The power of /yield/
comes from the fact that the method is in control when and how
often
it invokes /yield/ and what it passes on. Basically your
block is an anonymous callback function. For methods that simply do a
computation that does not need adjustment by custom code (the
callback) using /return/ is the most appropriate method.

Since with /yield/ the method is in control another typical idiom is
safe cleanup:

def x
yield 123
ensure
cleanup
end

File.open with block works that way.

Kind regards

robert