The value in ensure block is not returned

Here is the sample code:

irb(main):001:0> def test
irb(main):002:1> begin
irb(main):003:2* a = 1
irb(main):004:2> b = 2
irb(main):005:2> b
irb(main):006:2> ensure
irb(main):007:2* a
irb(main):008:2> end
irb(main):009:1> end
=> nil
irb(main):010:0> test
=> 2

I am expecting that 1 should be returned by is 2.

I also write another code to verify:

irb(main):011:0> def test
irb(main):012:1> begin
irb(main):013:2* a = 1
irb(main):014:2> b = 2
irb(main):015:2> b
irb(main):016:2> ensure
irb(main):017:2* a
irb(main):018:2> puts “hello”
irb(main):019:2> end
irb(main):020:1> end
=> nil
irb(main):022:0> test
hello
=> 2

So it is obviously that all codes in ensure block have been run. But the
return value is always the last value before ensure block.

On Mar 6, 2008, at 10:46 AM, Oliver P. wrote:

So it is obviously that all codes in ensure block have been run.
But the
return value is always the last value before ensure block.

That is the intended semantics. The ensure block doesn’t generate a
return value for the method. It is intended to contain code that should
be executed if the method returns normally or if the method is rolled
up during exception processing.

Gary W.

On 06.03.2008 16:46, Oliver P. wrote:

irb(main):009:1> end
=> nil
irb(main):010:0> test
=> 2

I am expecting that 1 should be returned by is 2.

Why should it? If you think about it you will see that it’s actually
good the way it is. The result of evaluating code in /ensure/ cannot be
returned under all circumstances (see Gary’s reply). And for normal
execution of a block of code you want the result of the code block to be
returned - not the result of /ensure/. The code in /ensure/ is intended
to do some cleanup that has to occur under all circumstances but not
interfere with normal processing.

So it is obviously that all codes in ensure block have been run. But the
return value is always the last value before ensure block.

Yes, no problem here.

Cheers

robert

Robert K. wrote:

On 06.03.2008 16:46, Oliver P. wrote:

irb(main):009:1> end
=> nil
irb(main):010:0> test
=> 2

I am expecting that 1 should be returned by is 2.

Why should it? If you think about it you will see that it’s actually
good the way it is. The result of evaluating code in /ensure/ cannot be
returned under all circumstances (see Gary’s reply). And for normal
execution of a block of code you want the result of the code block to be
returned - not the result of /ensure/. The code in /ensure/ is intended
to do some cleanup that has to occur under all circumstances but not
interfere with normal processing.

So it is obviously that all codes in ensure block have been run. But the
return value is always the last value before ensure block.

Yes, no problem here.

Cheers

robert

Ok. I see.

I am also curious what will happen if I change the return value in
ensure block. Here is my test code:

irb(main):003:0> def test
irb(main):004:1> begin
irb(main):005:2* a = 1
irb(main):006:2> b =2
irb(main):007:2> b
irb(main):008:2> ensure
irb(main):009:2* b += 3
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0> test
=> 2

It looks that the result value has been saved to a temp place before
running ensure block. Is that correct?

I also use global variable to test.

irb(main):014:0> @@value = 0
=> 0
irb(main):015:0> def test1
irb(main):016:1> begin
irb(main):017:2* @@value = 3
irb(main):018:2> ensure
irb(main):019:2* @@value = 8
irb(main):020:2> end
irb(main):021:1> end
=> nil
irb(main):023:0> test1
=> 3
irb(main):024:0> @@value
=> 8

Robert K. wrote:

2008/3/6, Oliver P. [email protected]:

Why should it? If you think about it you will see that it’s actually
Yes, no problem here.

irb(main):012:0> test
=> 2

It looks that the result value has been saved to a temp place before
running ensure block. Is that correct?

The return value is determined the very moment the block ends, which
means that the reference is saved (as always in Ruby). But since
you used Fixnums and simply reassigned to b (“b += 3”) this won’t be
visible. But

irb(main):001:0> def t
irb(main):002:1> s=“foo”
irb(main):003:1> ensure
irb(main):004:1* s.replace “see?”
irb(main):005:1> end
=> nil
irb(main):006:0> t
=> “see?”
irb(main):007:0>

In other words, of course you can change the object before it is
returned.

irb(main):021:1> end
=> nil
irb(main):023:0> test1
=> 3
irb(main):024:0> @@value
=> 8

Same story: you reassigned.

Cheers

robert

Ok I see. If I want to change the return value in ensure block, I need
to change the object itself in the last line before ensure, not just
reassign the varialbe. I also write another test code which can
demonstrate clearly:

irb(main):003:0> class A
irb(main):004:1> attr_accessor :value
irb(main):005:1> end
=> nil
irb(main):006:0> def test
irb(main):007:1> begin
irb(main):008:2* a = A.new
irb(main):009:2> a.value = 1
irb(main):010:2> a
irb(main):011:2> ensure
irb(main):012:2* a.value = 2
irb(main):013:2> end
irb(main):014:1> end
=> nil
irb(main):015:0> test
=> #<A:0xb7be48a0 @value=2>

I also did a test to try to do return in ensure block and it has higher
priority. Here is my test code:

irb(main):022:0> def test
irb(main):023:1> begin
irb(main):024:2* a = 1
irb(main):025:2> a
irb(main):026:2> ensure
irb(main):027:2* return 2
irb(main):028:2> end
irb(main):029:1> end
=> nil
irb(main):030:0> test
=> 2

Finally I think the best way is to avoid returning value in ensure block
and always put the return value in the last line of function or use
return directly.

Thanks for your replay.

2008/3/6, Oliver P. [email protected]:

Why should it? If you think about it you will see that it’s actually
Yes, no problem here.

irb(main):012:0> test
=> 2

It looks that the result value has been saved to a temp place before
running ensure block. Is that correct?

The return value is determined the very moment the block ends, which
means that the reference is saved (as always in Ruby). But since
you used Fixnums and simply reassigned to b (“b += 3”) this won’t be
visible. But

irb(main):001:0> def t
irb(main):002:1> s=“foo”
irb(main):003:1> ensure
irb(main):004:1* s.replace “see?”
irb(main):005:1> end
=> nil
irb(main):006:0> t
=> “see?”
irb(main):007:0>

In other words, of course you can change the object before it is
returned.

irb(main):021:1> end
=> nil
irb(main):023:0> test1
=> 3
irb(main):024:0> @@value
=> 8

Same story: you reassigned.

Cheers

robert