Kernel#exit raises an exception?

While I was working on embedding an interpreter I wrote a function to
catch unhandled exceptions and spit out some information on the
exception. While testing I noticed that the Kernel’s ‘exit’ method
actually seems to raise an exception.

Is this intended behavior? It struck me as somewhat odd and I had to
write a handler for it in my code (which is a pain in the bum if for no
other reason than it seems to lack elegance).

Khat H. wrote in post #1038120:

While I was working on embedding an interpreter I wrote a function to
catch unhandled exceptions and spit out some information on the
exception. While testing I noticed that the Kernel’s ‘exit’ method
actually seems to raise an exception.

Is this intended behavior?

$ ri Kernel#exit

 Initiates the termination of the Ruby script by raising the
 +SystemExit+ exception. This exception may be caught. The optional
 parameter is used to return a status code to the invoking
 environment.

It struck me as somewhat odd and I had to
write a handler for it in my code (which is a pain in the bum if for no
other reason than it seems to lack elegance).

Firstly: you can always call ‘exit!’ instead of ‘exit’, which bypasses
at-exit handlers and the rescuable exception.

Secondly: it is easy to tell Ruby to re-raise SystemExit, which means it
will take the standard action (of exiting with the given status code)

begin
exit 123
rescue SystemExit
raise
rescue Exception
puts ‘Other exceptions handled here’
end

Run this, echo $? and you’ll see the status 123.

So it’s intentional. Thank you.

I hear what you say, but shouldn’t that be something that gets handled
by raise?

My implementation isn’t what I’m worried about here, I already wrote the
handler, and the implementation is intended for end-users to write
scripts in. It’s just that I was surprised by what struck me as
non-intuitive behavior. I know exit! bypasses handlers. It always
struck me that this was a means of getting around ‘ensure’. I’ve always
viewed exit as being for exiting and raise being for raising exceptions.

I guess what I mean to ask is, why was it decided to do things this way
rather than the way I expected? What am I not understanding?

On Dec 24, 2011, at 15:20 , Khat H. wrote:

I hear what you say, but shouldn’t that be something that gets handled
by raise?

Raise doesn’t handle anything, rescue does. If you’re rescuing Exception
somewhere, you’re almost always doing something wrong.

Khat H. wrote in post #1038124:

I guess what I mean to ask is, why was it decided to do things this way
rather than the way I expected? What am I not understanding?

It seems both useful and logical to me (useful to have a mechanism for
catching ‘exit’, and logical that it should be handled in the same way
as exceptions)

I guess that what you expect depends on what you’ve seen in other
languages.

On Sun, Dec 25, 2011 at 12:20 AM, Khat H. [email protected]
wrote:

I hear what you say, but shouldn’t that be something that gets handled
by raise?

What do you mean by that? raise is only for raising exceptions.
Handling is done in rescue blocks. But there are also “ensure”
sections in begin end blocks. Does this help?

http://blog.rubybestpractices.com/posts/rklemme/003-The_Universe_between_begin_and_end.html

My implementation isn’t what I’m worried about here, I already wrote the
handler, and the implementation is intended for end-users to write
scripts in. It’s just that I was surprised by what struck me as
non-intuitive behavior. I know exit! bypasses handlers. It always
struck me that this was a means of getting around ‘ensure’. I’ve always
viewed exit as being for exiting and raise being for raising exceptions.
Is there something I’m missing?

If you think about it a little more I am sure you’ll notice what a
clever move it was to make exit raise an exception. That way,
regardless of where it is invoked all stacks are unwound and all
ensure blocks can do their job to do proper resource cleanup. For
example, if you invoke “exit” somewhere inside File.open { … } the
file descriptor is properly closed which includes flushing data
written to the IO object but not yet handed over to the OS.

Kind regards

robert

I’m saying that I think of raise as being the method for creating
exceptions and I think of exit as being the method for exiting the
interpreter.

It seems like I shouldn’t have used the word ‘handle’ anywhere near a
discussion on exceptions, I wasn’t saying that raise handles exceptions,
just that it’s responsible for creating them, so when I think about
triggering an exception I think about raise rather than exit.

I understand that the stack needs unwound and such, but I was just
surprised that exit would raise an exception rather than use a different
means of backing out ‘silently’ while still triggering the appropriate
behavior on the way down the stack.

It’s not a huge issue, just something that seems odd to me.

On Dec 26, 2011, at 16:40 , Khat H. wrote:

I understand that the stack needs unwound and such, but I was just
surprised that exit would raise an exception rather than use a different
means of backing out ‘silently’ while still triggering the appropriate
behavior on the way down the stack.

9999 % ruby -e ‘def f; exit 1; end; f’
10000 %

Looks silent to me.

Maybe you shouldn’t be rescuing Exception as I pointed out earlier.

I’m catching the exception code that is returned from ruby_exec_node()
in order to print out errors. This is necessary in order to produce
error information because the implementation does not have console
window and allows end-users to add scripts. ‘p’ and ‘print’ are handled
by message boxes and if ruby_exec_node() returns an error code then the
implementation gathers $!.message and $!.backtrace and pops up a message
box describing the error. There needs to be a way for the end users to
be informed of errors created by their scripts. If I don’t create a
handler for exit then the end-users won’t be able to use ‘exit’ in their
scripts without producing an ‘error’ message box.

The whole thrust of what I’m trying to say is that ‘raise’ is used to
raise an exception and ‘exit’ is used to exit the script. Presently
exit is just another way of raising an exception. This struck me as
non-intuitive, so I’m discussing it, that’s all. I don’t consider
explicitly exiting the script to be erroneous behavior.

… Are you trolling?

On Dec 27, 2011, at 02:50 , Khat H. wrote:

… Are you trolling?

Obviously… by trying to teach you something.

On Dec 27, 2011, at 00:21 , Khat H. wrote:

I’m catching the exception code that is returned from ruby_exec_node()
in order to print out errors. This is necessary in order to produce
error information because the implementation does not have console
window and allows end-users to add scripts. ‘p’ and ‘print’ are handled
by message boxes and if ruby_exec_node() returns an error code then the
implementation gathers $!.message and $!.backtrace and pops up a message
box describing the error. There needs to be a way for the end users to
be informed of errors created by their scripts. If I don’t create a
handler for exit then the end-users won’t be able to use ‘exit’ in their
scripts without producing an ‘error’ message box.

How will catching NoMemoryError, SignalException, or SystemExit help
you? As I said, catching Exception is almost always a mistake. It
certainly is in this case.

  • Exception
    • NoMemoryError
    • ScriptError
      • LoadError
      • NotImplementedError
      • SyntaxError
    • SignalException
      • Interrupt
    • StandardError (default for rescue)
      • ArgumentError
      • IOError
        • EOFError
      • IndexError
      • LocalJumpError
      • NameError
        • NoMethodError
      • RangeError
        • FloatDomainError
      • RegexpError
      • RuntimeError (default for raise)
      • SecurityError
      • SystemCallError
        • Errno::*
      • SystemStackError
      • ThreadError
      • TypeError
      • ZeroDivisionError
    • SystemExit
    • fatal

-----Messaggio originale-----
Da: Ryan D. [mailto:[email protected]]
Inviato: marted 27 dicembre 2011 22:26
A: ruby-talk ML
Oggetto: Re: Kernel#exit raises an exception?

On Dec 27, 2011, at 02:50 , Khat H. wrote:

… Are you trolling?

Obviously… by trying to teach you something.


Caselle da 1GB, trasmetti allegati fino a 3GB e in piu’ IMAP, POP3 e
SMTP autenticato? GRATIS solo con Email.it http://www.email.it/f

Sponsor:
Conto Arancio al 4,20%. Soldi sempre disponibili, zero spese, aprilo in
due minuti!
Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid920&d)-12