Yet another question on exceptions


#1

Hi,

If i use File::open to open/create a file objet, and if i use a block
with it, the file will be automatically close when the block ends:

Now, considering this buggy snippet:

begin
File.open(“my_file”) do |fic|
fic.puts(“bla”)
end
rescue Exception => e
STDERR.puts(e)
exit(1)
end

Here, the “not opened for writing” exception will be raised, the block
end will never be reached and the file will remain opened, isn’t it ?
To circumvent this, i have to make fic a global variable and put the
appropriate code in a ensure clause (or open a begin/ensure in the
File.open block to close the file… too bad)

So, my question is: what’s the benefit of this idiom versus this one:

begin
fd = File.new(“my_file”)

rescue Exception => e
STDERR.puts(e)
exit(1)
ensure
fd.close if fd and not fd.closed?
end

Is there something i’ve missed?


#2

Eric J. wrote:

end

end

Is there something i’ve missed?

Yes, as Grennady pointed out. The benefit of using File#open with a
block
is exactly that you do not have to do the closing yourself. Less code,
less errors.

Btw, your first example is overly complex. This does the same:

File.open(“my_file”) do |fic|
fic.puts(“bla”)
end

17:53:40 [~]: ruby -e ‘File.open(“dsdsd”) {|io| p io}’ ; echo $?
-e:1:in `initialize’: No such file or directory - dsdsd (Errno::ENOENT)
from -e:1
1
17:53:55 [~]:

Kind regards

robert

#3

“Robert K.” removed_email_address@domain.invalid writes:

Btw, your first example is overly complex. This does the same:

File.open(“my_file”) do |fic|
fic.puts(“bla”)
end

Actually, i took the habit to always handle exceptions myself, hence
the block begin/rescue…

Furthermore, it was a toy exemple: i like my scripts exit with
different values for different problems.


#4

David V. removed_email_address@domain.invalid writes:

Well, File.open in the block version will reraise the exception precisely to
let you do that, it’s not supposed to silently ignore errors.

Ok, perhaps i’m not clear or perhaps i’ve missed something…

Suppose i want my script exit with different values depending on the
error cases:

% ruby -e ‘File.open(“no.txt”) {|f| line = f.gets}’
-e:1:in initialize': No such file or directory - no.txt (Errno::ENOENT) from -e:1 % echo $? 1 % ruby -e 'File.open("yes.txt") {|f| f.puts("bla")}' -e:1:inwrite’: not opened for writing (IOError)
from -e:1
from -e:1
[titine]:~/Desktop % echo $?
1

As it’s clearly not the same error, i don’t want the same return
status. As i don’t know how to manage this gracefully with Ruby, i’m
using a well-know idiom (at least for me…). That said, if there a
more rubywaying solution, i buy it.


#5

2006/2/10, Eric J. removed_email_address@domain.invalid:

% ruby -e ‘File.open(“no.txt”) {|f| line = f.gets}’

As it’s clearly not the same error, i don’t want the same return
status. As i don’t know how to manage this gracefully with Ruby, i’m
using a well-know idiom (at least for me…). That said, if there a
more rubywaying solution, i buy it.

Actually, catching those exceptions and exiting depending on them is
perfectly ok. Although I would question the habit to always handle
exceptions yourself. Often it’s not needed and one can end up handling
exceptions too far down the call hierarchy. The nice thing about
Ruby’s exceptions is that they are unchecked (borrowing this term from
Java), which basically means that they are not declared. At times this
can make it difficult to figure what exceptions can be thrown from a
method but surprisingly often this is not an issue (at least not for
me, maybe in larger software systems).

Kind regards

robert

PS: A variant you could do for multiple return values to avoid lots of
similar rescue clauses:

RV = Hash.new(1).merge(
Exception => 1,
ERRNO::Foo => 2
)

begin

rescue Exception => e
STDERR.puts e
exit RV[e.class]
end


#6

DÅ?a Piatok 10 Február 2006 19:43 Eric J. napísal:

-e:1:in `initialize’: No such file or directory - no.txt (Errno::ENOENT)
As it’s clearly not the same error, i don’t want the same return
status. As i don’t know how to manage this gracefully with Ruby, i’m
using a well-know idiom (at least for me…). That said, if there a
more rubywaying solution, i buy it.

If you want to assign your own error codes, feel free to do so. As I
said,
that’s why File will reraise the exception. What I wanted to emphasise
is
that you don’t need to take care of cleanup of file handles while still
being
able to handle errors as you want to.

There’s nothing wrong with what you wrote in the original post, as long
as you
keep to printing the error message to standard error to keep with
conventions.


#7

DÅ?a Piatok 10 Február 2006 18:33 Eric J. napísal:

Furthermore, it was a toy exemple: i like my scripts exit with
different values for different problems.

Well, File.open in the block version will reraise the exception
precisely to
let you do that, it’s not supposed to silently ignore errors.

Isn’t there a POSIX C header that defines various types of standard
error
codes for programs to return? In case I’m not imagining things, you
might
want to look into it and whether we can access those constants from Ruby
to
do things The Right Way.