"ensure" hiding actual error

N

Nit Khair

In my main program I have a "begin ensure end".
The "ensure" releases some resources.

If there is a syntax error somewhere deep, the program comes to 'ensure'
and shows me an error in the 'ensure', not the original error. Only if I
block out the 'ensure', does the actual error show.

I tried "rescue" with Exception, StandardError and ScriptError to print
the exception, but flow never reaches the 'rescue' block, it jumps ahead
to "ensure".
 
R

Robert Klemme

2008/10/1 Nit Khair said:
In my main program I have a "begin ensure end".
The "ensure" releases some resources.

If there is a syntax error somewhere deep, the program comes to 'ensure'
and shows me an error in the 'ensure', not the original error. Only if I
block out the 'ensure', does the actual error show.

I tried "rescue" with Exception, StandardError and ScriptError to print
the exception, but flow never reaches the 'rescue' block, it jumps ahead
to "ensure".

This sounds strange because syntax errors should be caught earlier -
unless they stem from an "require" or "load". Can you post a short
example that reproduces the error?

Kind regards

robert
 
N

Nit Khair

Robert said:
This sounds strange because syntax errors should be caught earlier -
unless they stem from an "require" or "load". Can you post a short
example that reproduces the error?

Kind regards

robert

Could you elaborate on that? At the moment, I am requiring a Module and
inheriting from a class. And the syntax error was in one of them.
However, as i said, when i remove the 'ensure' it correctly shows the
error in the relevant class.

I cannot recall if this error occurred when i had everything in one.
Will try to give a short sample. It's an ncurses-ruby program.
 
R

Robert Klemme

2008/10/1 Nit Khair said:
Could you elaborate on that?

When Ruby interpreter loads a file it checks syntax (you can do
yourself with "ruby -c <script>"). If there is a syntax error that
will be shown before execution starts at all. If you require a file
and there is a syntax error in that there you will see an exception
stemming from the 'require':

1. error in main, 2. error in required:

15:20:13 OPSC_Gold_bas_dev_R1.2.3$ ruby -e 'puts 111+; require
ARGV.shift' <(echo /)
-e:1: syntax error, unexpected ';'
puts 111+; require ARGV.shift
^
15:20:22 OPSC_Gold_bas_dev_R1.2.3$ ruby -e 'puts 111; require
ARGV.shift' <(echo /)
111
-e:1:in `require': /dev/fd/63.rb:1: unterminated string meets end of
file (SyntaxError)
/dev/fd/63.rb:1: syntax error, unexpected tSTRING_END, expecting
tSTRING_CONTENT or tREGEXP_END or tSTRING_DBEG or tSTRING_DVAR
from -e:1
15:20:26 OPSC_Gold_bas_dev_R1.2.3$

Cheers

robert
 
N

Nit Khair

I've tried to make a trivial case. Variable x is not initialized.

#!/usr/bin/env ruby -w

begin
@test = x


ensure
@test.strip
end

The error I get is:

x.rb:8: warning: instance variable @test not initialized
x.rb:8: undefined method `strip' for nil:NilClass (NoMethodError)


Now in real life, "@test = " calls a method elsewhere which may call
other methods. So i am clueless as to where the error actually is.

Now let's comment the ensure word. The new error message is:

x.rb:4: undefined local variable or method `x' for main:Object
(NameError)

So this is currently my only solution.
In this particular case, I now add (before the ensure):

rescue Exception => boom
$stderr.print boom

and now I get the error. However, in my real curses program, it skips
the rescue clause and continues to go into the ensure.
 
T

Thomas B.

Nit said:
Now in real life, "@test = " calls a method elsewhere which may call
other methods. So i am clueless as to where the error actually is.

You caused another exception inside your ensure clause, so the previous
one got lost, so that's your mistake. If you want the original exception
to live to tell the tale, you cannot raise another in your ensure
clause. But if your ensure clause was correct, there wouldn't be any
problems with handling correctly the original exception.

TPR.
 
R

Robert Klemme

2008/10/1 Thomas B. said:
You caused another exception inside your ensure clause, so the previous
one got lost, so that's your mistake. If you want the original exception
to live to tell the tale, you cannot raise another in your ensure
clause. But if your ensure clause was correct, there wouldn't be any
problems with handling correctly the original exception.

Adding to that: an uninitialized variable does not cause a syntax
error. IIRC initially this was about a syntax error.

Cheers

robert
 
N

Nit Khair

I am not following you. How have i caused another exception in the
ensure clause. I am not raising an exception in the ensure. The ensure
clause only has some statement to free resources. as in :


begin
my_form = create_....

ensure
my_form.free_form.
...
end


In the example i gave you, the stderr.print is printing the error from
above, but in my original ncurses program, it seems to directly go to
the ensure.

Let's say in my ensure I said:

my_form.free_form if !my_form.nil?
then the program would just terminate silently.

Adding to that: an uninitialized variable does not cause a syntax
error. IIRC initially this was about a syntax error.

Okay, i was trying to give you a simple example. Sometimes it is a
variable - i may misspell it, or in some cases it is a syntax error.

Even currently as I am refactoring my code, I am sometimes getting the
correct error, sometimes I have to comment out "ensure" to get the
error.
Cheers

robert

Perhaps I should ask the question differently. Am i doing something
wrong, am i using the ensure clause incorrectly (the samples I started
with released these structures in the ensure). This is my first major
ruby app.
Thanks a lot for your time, Robert!
 
G

Glen Holcomb

[Note: parts of this message were removed to make it a legal post.]

I am not following you. How have i caused another exception in the
ensure clause. I am not raising an exception in the ensure. The ensure
clause only has some statement to free resources. as in :


begin
my_form = create_....

ensure
my_form.free_form.
...
end

What happens here if my_form never got a value because there was an error
previous that made create_... invalid?

What Thomas is saying is that there is an exception being raised by the code
present in your ensure block.
 
N

Nit Khair

Glen said:
What happens here if my_form never got a value because there was an
error
previous that made create_... invalid?

What Thomas is saying is that there is an exception being raised by the
code
present in your ensure block.
Fine. I get that. So is there a better or correct way of doing this so
that I get the original error that was raised.

Aaaah. so you mean if i check for my_form before freeing, then ... since
no new exception is raised, the original exception will be displayed.
So I _should_ say:

ensure
if !my_form.nil?
my_form.free ... etc
end
 
T

Thomas B.

Nit said:
Robert Klemme wrote:
I am not following you. How have i caused another exception in the
ensure clause. I am not raising an exception in the ensure. The ensure
clause only has some statement to free resources. as in :

In the example you gave, where your ensure clause is @test.strip, you
did raise another exception, the "undefined method `strip' for
nil:NilClass (NoMethodError)" namely. Your ensure clause should do its
best not to raise any exception, or else the original exception is lost,
as you see.
Perhaps I should ask the question differently. Am i doing something
wrong, am i using the ensure clause incorrectly (the samples I started
with released these structures in the ensure). This is my first major
ruby app.

You are using the ensure correctly. The problem is that under some
circumstances the code in your ensure clause raises an exception. Maybe
you should use a separate begin rescue end inside your ensure clause.

TPR.
 
G

Glen Holcomb

[Note: parts of this message were removed to make it a legal post.]

Fine. I get that. So is there a better or correct way of doing this so
that I get the original error that was raised.

Aaaah. so you mean if i check for my_form before freeing, then ... since
no new exception is raised, the original exception will be displayed.
So I _should_ say:

ensure
if !my_form.nil?
my_form.free ... etc
end
Yeah!
 
S

Stefan Lang

2008/10/1 Nit Khair said:
Fine. I get that. So is there a better or correct way of doing this so
that I get the original error that was raised.

Aaaah. so you mean if i check for my_form before freeing, then ... since
no new exception is raised, the original exception will be displayed.
So I _should_ say:

Generally, the right way is to put the initialization _before_
the begin/ensure block:

resource = init_resource
begin
# do something with resource
ensure
resource.close
end

If all you do in the ensure block is to clean up the resource,
it is useless to put the resource initialization in the begin/ensure
block, because if the initialization fails, there's nothing to
cleanup anyway.

Stefan
 
N

Nit Khair

Stefan said:
Generally, the right way is to put the initialization _before_
the begin/ensure block:

resource = init_resource
begin
# do something with resource
ensure
resource.close
end

If all you do in the ensure block is to clean up the resource,
it is useless to put the resource initialization in the begin/ensure
block, because if the initialization fails, there's nothing to
cleanup anyway.

Stefan

Very interesting answer. Let me be honest -- I've been lost as to where
to start the begin block. Is there any guideline in ruby?

I spent many years in Java where the style was:

try {
resource = init_resource
} catch (exception) {}
finally {
resource.close
}

I was following that pattern.

My apps basically:

a. create fields, forms and windows.
b. call key_handler loop
c. cleanup resources when key_handler quits

thanks a lot for valuable thoughts.
 
D

Dave Thomas

I spent many years in Java where the style was:

try {
resource = init_resource
} catch (exception) {}
finally {
resource.close
}

This is common in Java, but it is incorrect.

What happens if init_resource() throws an exception?


Dave
 
N

Nit Khair

Dave said:
This is common in Java, but it is incorrect.

What happens if init_resource() throws an exception?


Dave

Oops I forgot to mention that in finally {} one would check for resource
not being nil. Corrected above.
 
R

Robert Klemme

Oops I forgot to mention that in finally {} one would check for resource
not being nil. Corrected above.

The pattern is still broken - or put it differently: overly complex.
This is easier and as safe - and you can make the resource final and
avoid accidental reassignment:

final Resource res = initResource();
try {
res.use();
res.use();
res.use();
res.use();
}
finally {
res.cleanup();
}

Cheers

robert
 
N

Nit Khair

Robert said:
The pattern is still broken - or put it differently: overly complex.
This is easier and as safe - and you can make the resource final and
avoid accidental reassignment:

final Resource res = initResource();
try {
res.use();
res.use();
res.use();
res.use();
}
finally {
res.cleanup();
}

Cheers

robert

Actually, I have left Java 4 years back. However, that being my last
programming language i still tend to thing in that way. IIRC, the above
pattern is used commonly because most, if not all, books gave it in
their samples. Take file opening or a database connection, for example.

Since it can throw a file not found exception, or a database connection
etc exception, the JDBC tutorials will recommend:

declare db variable
try {
db = create_dbconnection(...)
db.use

}
catch (ex){}
finally { cleanup code }


Anyway, I'd like to ask, if I use your suggested pattern of opening a
file or creating a resource before a begin/rescue/ensure block, would
that not mean i am not trapping failures from that. (I am just unused to
thinking this way! Could you point me to some code that illustrates
this.

Also, is there a quick way to know what exceptions a method can throw ?
Or is that not relevant ?
 
R

Robert Klemme

Actually, I have left Java 4 years back. However, that being my last
programming language i still tend to thing in that way. IIRC, the above
pattern is used commonly because most, if not all, books gave it in
their samples. Take file opening or a database connection, for example.

Well, books are dead wood. You always have to apply your own reasoning.
It is not too uncommon for multiple books repeating the same error.
In my experience it is best to take every advice with a grain of salt
and apply own reasoning.
Since it can throw a file not found exception, or a database connection
etc exception, the JDBC tutorials will recommend:

declare db variable
try {
db = create_dbconnection(...)
db.use

}
catch (ex){}
finally { cleanup code }


Anyway, I'd like to ask, if I use your suggested pattern of opening a
file or creating a resource before a begin/rescue/ensure block, would
that not mean i am not trapping failures from that. (I am just unused to
thinking this way! Could you point me to some code that illustrates
this.

Since we did not talk about rescue clauses so far (apart from your
example above) there was never exception handling - regardless of
placement of ensure / finally blocks.

When using my pattern you can catch errors more selectively:

try {
Connection conn = getConnection();
try {
Statement st = conn.createStatement();
...
}
catch (SQLException e) {
System.err.println("Conn use error: " + e.getMessage());
}
finally {
close(conn);
}
}
catch (SQLException e) {
System.err.println("Conn init error: " + e.getMessage());
}

If you do not like the nesting you can refactor and extract the inner
part into another method.
Also, is there a quick way to know what exceptions a method can throw ?
Or is that not relevant ?

In Ruby: No, you would have to look at the code of a method and all
methods which were called etc. Documentation is the fastest way I know of.

In Java: all methods can throw sub classes of all the checked exceptions
listed in the signature plus all sub classes of RuntimeException and Error.

Kind regards

robert
 

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

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top