From: Austin Ziegler via ruby-core <ruby-core@ml.ruby-lang.org>
To: Ruby developers <ruby-core@ml.ruby-lang.org>
Cc: Rodrigo Rosenfeld Rosas <rr.rosas@gmail.com>,
Austin Ziegler <halostatue@gmail.com>
Subject: [ruby-core:119639] Re: Behavior of raising from rescue blocks when multiple rescue blocks exist
Date: Tue, 29 Oct 2024 14:07:08 -0400 [thread overview]
Message-ID: <CAJ4ekQuDv7xsVH0-UHvmzMB5rFSjXLy5MgWoB5gCcUDBk3jYPQ@mail.gmail.com> (raw)
In-Reply-To: <CAGmv+wLXtNng-RwDVCKsAVLAoHJ-Kx80L-Md_QLSiFty6izo=Q@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 11430 bytes --]
RuntimeError is a descendant of StandardError, and rescues happen exactly
once per exception handling block.
That is, your first code example will never hit RuntimeError because it's
swallowed by the implicit StandardError.
Here's a class tree of Exception from my local irb:
- Exception
|- ErrorHighlight::Spotter::NonAscii
|- IRB::Abort
|- IRB::LoadAbort
|- NoMemoryError
|- ScriptError
| |- LoadError
| | `- Gem::LoadError
| | |- Gem::ConflictError
| | `- Gem::MissingSpecError
| | `- Gem::MissingSpecVersionError
| |- NotImplementedError
| `- SyntaxError
|- SecurityError
|- SignalException
| `- Interrupt
|- StandardError
| |- ArgumentError
| | |- Gem::Requirement::BadRequirementError
| | |- IO::Buffer::MaskError
| | `- UncaughtThrowError
| |- EncodingError
| | |- Encoding::CompatibilityError
| | |- Encoding::ConverterNotFoundError
| | |- Encoding::InvalidByteSequenceError
| | `- Encoding::UndefinedConversionError
| |- FiberError
| |- Fiddle::Error
| | |- Fiddle::ClearedReferenceError
| | `- Fiddle::DLError
| |- Gem::Molinillo::ResolverError
| | |- Gem::Molinillo::CircularDependencyError
| | |- Gem::Molinillo::NoSuchDependencyError
| | `- Gem::Molinillo::VersionConflict
| |- Gem::TSort::Cyclic
| |- IOError
| | |- EOFError
| | `- IO::TimeoutError
| |- IRB::CantChangeBinding
| |- IRB::CantReturnToNormalMode
| |- IRB::Command::CommandArgumentError
| |- IRB::IllegalParameter
| |- IRB::IrbAlreadyDead
| |- IRB::IrbSwitchedToCurrentThread
| |- IRB::NoSuchJob
| |- IRB::RubyLex::TerminateLineInput
| |- IRB::SourceFinder::EvaluationError
| |- IRB::UndefinedPromptMode
| |- IRB::UnrecognizedSwitch
| |- IndexError
| | |- KeyError
| | `- StopIteration
| | |- ClosedQueueError
| | `- Ractor::ClosedError
| |- JSON::JSONError
| | |- JSON::GeneratorError
| | |- JSON::MissingUnicodeSupport
| | `- JSON::ParserError
| | `- JSON::NestingError
| | `- JSON::CircularDatastructure
| |- LocalJumpError
| |- Math::DomainError
| |- NameError
| | `- NoMethodError
| |- NoMatchingPatternError
| | `- NoMatchingPatternKeyError
| |- RangeError
| | `- FloatDomainError
| |- RegexpError
| | `- Regexp::TimeoutError
| |- Reline::ConfigEncodingConversionError
| |- Reline::Terminfo::TerminfoError
| |- Ripper::TokenPattern::Error
| | |- Ripper::TokenPattern::CompileError
| | `- Ripper::TokenPattern::MatchError
| |- RuntimeError
| | |- FrozenError
| | |- Gem::Exception
| | | |- Gem::CommandLineError
| | | |- Gem::DependencyError
| | | | |- Gem::DependencyResolutionError
| | | | `- Gem::UnsatisfiableDependencyError
| | | |- Gem::DependencyRemovalException
| | | |- Gem::DocumentError
| | | |- Gem::EndOfYAMLException
| | | |- Gem::FilePermissionError
| | | |- Gem::FormatException
| | | |- Gem::GemNotFoundException
| | | | `- Gem::SpecificGemNotFoundException
| | | |- Gem::GemNotInHomeException
| | | |- Gem::ImpossibleDependenciesError
| | | |- Gem::InstallError
| | | | `- Gem::RuntimeRequirementNotMetError
| | | |- Gem::InvalidSpecificationException
| | | |- Gem::OperationNotSupportedError
| | | |- Gem::RemoteError
| | | |- Gem::RemoteInstallationCancelled
| | | |- Gem::RemoteInstallationSkipped
| | | |- Gem::RemoteSourceException
| | | |- Gem::RequestSet::Lockfile::ParseError
| | | |- Gem::RubyVersionMismatch
| | | |- Gem::UninstallError
| | | |- Gem::UnknownCommandError
| | | |- Gem::VerificationError
| | | `- Gem::WebauthnVerificationError
| | |- IO::Buffer::AccessError
| | |- IO::Buffer::AllocationError
| | |- IO::Buffer::InvalidatedError
| | |- IO::Buffer::LockedError
| | |- RDoc::Error
| | |- Ractor::Error
| | | |- Ractor::IsolationError
| | | |- Ractor::MovedError
| | | |- Ractor::RemoteError
| | | `- Ractor::UnsafeError
| | `- Reline::Config::InvalidInputrc
| |- SystemCallError
| | |- Errno::E2BIG
| | |- Errno::EACCES
| | |- Errno::EADDRINUSE
| | |- Errno::EADDRNOTAVAIL
| | |- Errno::EAFNOSUPPORT
| | |- Errno::EAGAIN
| | | |- IO::EAGAINWaitReadable
| | | `- IO::EAGAINWaitWritable
| | |- Errno::EALREADY
| | |- Errno::EAUTH
| | |- Errno::EBADARCH
| | |- Errno::EBADEXEC
| | |- Errno::EBADF
| | |- Errno::EBADMACHO
| | |- Errno::EBADMSG
| | |- Errno::EBADRPC
| | |- Errno::EBUSY
| | |- Errno::ECANCELED
| | |- Errno::ECHILD
| | |- Errno::ECONNABORTED
| | |- Errno::ECONNREFUSED
| | |- Errno::ECONNRESET
| | |- Errno::EDEADLK
| | |- Errno::EDESTADDRREQ
| | |- Errno::EDEVERR
| | |- Errno::EDOM
| | |- Errno::EDQUOT
| | |- Errno::EEXIST
| | |- Errno::EFAULT
| | |- Errno::EFBIG
| | |- Errno::EFTYPE
| | |- Errno::EHOSTDOWN
| | |- Errno::EHOSTUNREACH
| | |- Errno::EIDRM
| | |- Errno::EILSEQ
| | |- Errno::EINPROGRESS
| | | |- IO::EINPROGRESSWaitReadable
| | | `- IO::EINPROGRESSWaitWritable
| | |- Errno::EINTR
| | |- Errno::EINVAL
| | |- Errno::EIO
| | |- Errno::EISCONN
| | |- Errno::EISDIR
| | |- Errno::ELAST
| | |- Errno::ELOOP
| | |- Errno::EMFILE
| | |- Errno::EMLINK
| | |- Errno::EMSGSIZE
| | |- Errno::EMULTIHOP
| | |- Errno::ENAMETOOLONG
| | |- Errno::ENEEDAUTH
| | |- Errno::ENETDOWN
| | |- Errno::ENETRESET
| | |- Errno::ENETUNREACH
| | |- Errno::ENFILE
| | |- Errno::ENOATTR
| | |- Errno::ENOBUFS
| | |- Errno::ENODATA
| | |- Errno::ENODEV
| | |- Errno::ENOENT
| | |- Errno::ENOEXEC
| | |- Errno::ENOLCK
| | |- Errno::ENOLINK
| | |- Errno::ENOMEM
| | |- Errno::ENOMSG
| | |- Errno::ENOPOLICY
| | |- Errno::ENOPROTOOPT
| | |- Errno::ENOSPC
| | |- Errno::ENOSR
| | |- Errno::ENOSTR
| | |- Errno::ENOSYS
| | |- Errno::ENOTBLK
| | |- Errno::ENOTCONN
| | |- Errno::ENOTDIR
| | |- Errno::ENOTEMPTY
| | |- Errno::ENOTRECOVERABLE
| | |- Errno::ENOTSOCK
| | |- Errno::ENOTSUP
| | |- Errno::ENOTTY
| | |- Errno::ENXIO
| | |- Errno::EOPNOTSUPP
| | |- Errno::EOVERFLOW
| | |- Errno::EOWNERDEAD
| | |- Errno::EPERM
| | |- Errno::EPFNOSUPPORT
| | |- Errno::EPIPE
| | |- Errno::EPROCLIM
| | |- Errno::EPROCUNAVAIL
| | |- Errno::EPROGMISMATCH
| | |- Errno::EPROGUNAVAIL
| | |- Errno::EPROTO
| | |- Errno::EPROTONOSUPPORT
| | |- Errno::EPROTOTYPE
| | |- Errno::EPWROFF
| | |- Errno::ERANGE
| | |- Errno::EREMOTE
| | |- Errno::EROFS
| | |- Errno::ERPCMISMATCH
| | |- Errno::ESHLIBVERS
| | |- Errno::ESHUTDOWN
| | |- Errno::ESOCKTNOSUPPORT
| | |- Errno::ESPIPE
| | |- Errno::ESRCH
| | |- Errno::ESTALE
| | |- Errno::ETIME
| | |- Errno::ETIMEDOUT
| | |- Errno::ETOOMANYREFS
| | |- Errno::ETXTBSY
| | |- Errno::EUSERS
| | |- Errno::EXDEV
| | `- Errno::NOERROR
| |- ThreadError
| |- TypeError
| `- ZeroDivisionError
|- SystemExit
| `- Gem::SystemExitException
|- SystemStackError
`- fatal
-a
On Tue, Oct 29, 2024 at 8:48 AM Rodrigo Rosenfeld Rosas via ruby-core <
ruby-core@ml.ruby-lang.org> wrote:
> Hello, I couldn't find any documentation about the subject, so I thought
> this behavior should be probably documented.
>
> Given the following code:
>
> def raise_error
> raise "runtime error message"
> rescue => e
> "StandardError: #{e.message}"
> rescue RuntimeError => e
> puts "RuntimeError raised: #{e.message}"
> raise StandardError, "standard error message"
> end
>
> # same, but the order of the rescue blocks are inverted
> def raise_error2
> raise "runtime error message"
> rescue RuntimeError => e
> puts "RuntimeError raised: #{e.message}"
> raise StandardError, "standard error message"
> rescue => e
> "StandardError: #{e.message}"
> end
>
> p ["raise_error", raise_error ]
>
> begin
> p ["raise_error2", raise_error2]
> rescue => e
> puts "raise_error2 raised: #{e.message}"
> end
>
> When we run it, this is the output in Ruby 3.3.5:
>
> ["raise_error", "StandardError: runtime error message"]
>
> RuntimeError raised: runtime error message
>
> raise_error2 raised: standard error message
>
>
> In the first case (raise_error), the code raised from the RuntimeError
> rescue block is rescued by the StandardError block, but when inverting the
> order of the rescue blocks (raise_error2) then this won't happen.
>
> Is this part of the specs? Is this behavior documented somewhere? Could
> this behavior differ in different Ruby implementations and versions? Or can
> we rely on such behavior?
>
>
> This chapter doesn't include such case in its examples:
>
> https://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html
>
> Or this documentation about Exceptions:
>
> https://ruby-doc.org/3.3.5/syntax/exceptions_rdoc.html
>
> Is there a recommended way for wrapping exceptions into a particular one
> and then handling that exception from within the same method rescue blocks?
> Or is this considered a bad practice?
>
>
> ______________________________________________
> ruby-core mailing list -- ruby-core@ml.ruby-lang.org
> To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
> ruby-core info --
> https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/
--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/ • http://twitter.com/halostatue
[-- Attachment #1.2: Type: text/html, Size: 17864 bytes --]
[-- Attachment #2: Type: text/plain, Size: 254 bytes --]
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/
next prev parent reply other threads:[~2024-10-29 18:09 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-29 12:42 [ruby-core:119637] " Rodrigo Rosenfeld Rosas via ruby-core
2024-10-29 18:07 ` Austin Ziegler via ruby-core [this message]
2024-10-29 19:22 ` [ruby-core:119640] " Rodrigo Rosenfeld Rosas via ruby-core
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAJ4ekQuDv7xsVH0-UHvmzMB5rFSjXLy5MgWoB5gCcUDBk3jYPQ@mail.gmail.com \
--to=ruby-core@ml.ruby-lang.org \
--cc=halostatue@gmail.com \
--cc=rr.rosas@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).