[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Yet another question on exceptions

Eric Jacoboni

2/10/2006 12:54:00 AM

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?
--
Eric Jacoboni, ne il y a 1442972561 secondes
6 Answers

Robert Klemme

2/10/2006 4:55:00 PM

0

Eric Jacoboni wrote:
> 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?

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

Eric Jacoboni

2/10/2006 5:29:00 PM

0

"Robert Klemme" <bob.news@gmx.net> 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.
--
Eric Jacoboni, ne il y a 1443032789 secondes

David Vallner

2/10/2006 6:18:00 PM

0

Dna Piatok 10 Február 2006 18:33 Eric Jacoboni napísal:
> "Robert Klemme" <bob.news@gmx.net> 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.

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.


Eric Jacoboni

2/10/2006 6:38:00 PM

0

David Vallner <david@vallner.net> 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:in `write': 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.

--
Eric Jacoboni, ne il y a 1443036511 secondes

Robert Klemme

2/10/2006 7:04:00 PM

0

2006/2/10, Eric Jacoboni <jaco@neottia.net>:
> David Vallner <david@vallner.net> 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:in `write': 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.

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

--
Have a look: http://www.flickr.com/photos/fu...


David Vallner

2/10/2006 7:53:00 PM

0

Dna Piatok 10 Február 2006 19:43 Eric Jacoboni napísal:
> David Vallner <david@vallner.net> 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:in `write': 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.

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.