ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
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/

  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).