the value in ensure block is not returned

O

Oliver Peng

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.
 
G

Gary Wright

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 Wright
 
R

Robert Klemme

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.

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
 
O

Oliver Peng

Robert said:
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.


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
 
R

Robert Klemme

2008/3/6 said:
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?

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.
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

Same story: you reassigned.

Cheers

robert
 
O

Oliver Peng

Robert said:
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.


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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top