Forum: Ruby Yet another question on exceptions

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
C5eecd44fa818c7985d4f31bc2c42ac9?d=identicon&s=25 Eric Jacoboni (Guest)
on 2006-02-10 17:03
(Received via mailing list)
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?
5befe95e6648daec3dd5728cd36602d0?d=identicon&s=25 Robert Klemme (Guest)
on 2006-02-10 17:58
(Received via mailing list)
Eric Jacoboni 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
C5eecd44fa818c7985d4f31bc2c42ac9?d=identicon&s=25 Eric Jacoboni (Guest)
on 2006-02-10 18:33
(Received via mailing list)
"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.
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-02-10 19:17
(Received via mailing list)
DÅ?a Piatok 10 Február 2006 18:33 Eric Jacoboni 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.
C5eecd44fa818c7985d4f31bc2c42ac9?d=identicon&s=25 Eric Jacoboni (Guest)
on 2006-02-10 19:43
(Received via mailing list)
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.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2006-02-10 20:04
(Received via mailing list)
2006/2/10, Eric Jacoboni <jaco@neottia.net>:
> % 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
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-02-10 20:53
(Received via mailing list)
DÅ?a Piatok 10 Február 2006 19:43 Eric Jacoboni 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.
This topic is locked and can not be replied to.