Feature #8912

Exception.raise

Added by Tsuyoshi Sawada 7 months ago. Updated 7 months ago.

[ruby-core:57198]
Status:Feedback
Priority:Normal
Assignee:-
Category:-
Target version:-

Description

=begin
When we have a custom exception class with a custom (({initialize})) method whose arity is not (({1})):

class MyException < StandardError
  def initialize x, y
    super("Something went wrong with #{x.inspect} because #{y}, blah blah")
  end
end

in order to raise it, we have to create a new instance of it explicitly using (({new})), and embed that under (({Kernel#raise})).

raise(MyException.new(:foo, :bar))

This is inconvenient, and does not look object oriented. I propose that there should be (({Exception#raise})), which is public, so that we can do:

MyException.raise(:foo, :bar)

A Ruby implementation may be like this:

class Exception
  def self.raise *args; Kernel.send(:raise, *args) end
end

This will disallow us from calling the private method (({Kernel#raise})) (without an explicit receiver) within the context of an (({Exception})) class unless we use (({send})), but I think such use case is rare, and that should not be a problem.
=end

History

#1 Updated by Tsuyoshi Sawada 7 months ago

=begin
I made a mistake. I meant, an implementation may be:

class Exception
  def self.raise *args; Kernel.send(:raise, new(*args)) end
end

=end

#2 Updated by Yukihiro Matsumoto 7 months ago

  • Status changed from Open to Feedback

I am not sure if there's significant practical difference between

raise(MyException.new(:foo,:bar))

and

MyException.raise(:foo,:bar)

It seems very trivial for me.

I guess you hate to call the function (private method of Kernel) #raise?
Can you elaborate?

Matz.

#3 Updated by Tsuyoshi Sawada 7 months ago

matz, thank you for the comment.

I think that raising an error is a peculiar property of an instance of Exception. Every time we raise, we raise one and only one exception, and nothing else. No other type of object can be raised. From object oriented point of view, this tells us that the method should belong to the Exception class, not Kernel.

Furthermore, it is rare that we want to create an instance of an Exception without raising it. If Exception#new exists, there is even more reason to have Exception#raise. The latter is more usable than the former.

In fact, method "raise" should be considered as a constructor with a side effect (of raising the exception). Various constructors are defined as class methods, and I don't understand why that is not the case for exceptions.

From a practical point of view, I feel repeating the extra pairs of parentheses cumbersome.

#4 Updated by Nobuyoshi Nakada 7 months ago

  • Subject changed from Exception#raise to Exception.raise
  • Description updated (diff)

=begin
How can you pass erred location and backtrace?

You can call (({Kernel.raise})) as:
class Exception
def self.raise(args) Kernel.raise(new(args)) end
end

And you seem talking about (({Exception.raise})), not (({Exception#raise})).
=end

#5 Updated by Yukihiro Matsumoto 7 months ago

As Nobu pointed out, we need to use the proper terms:

  • Exception.raise instead of Exception#raise
  • Exception.new instead of Exception#new

We have to distinguish class methods and instance methods.

Then I think we need a way to separate allocating and raising.
By providing Exception.raise (and discouraging Kernel#raise), there's no sufficient way to raise pre-allocated exceptions.
Kernel raise takes either exception class or exception instance.

If we really need to emphasize OO way in raising exception as you claim, I'd rather add Exception#raise, i.e.

MyException.new(:foo,:bar).raise

But in reality, I prefer traditional

raise MyException.new(:foo,:bar)

because 'raise' is a core operation, that often is implemented by the reserved keyword in other languages,
and maybe we will replace it by (somewhat-soft) keyword in the future.

Matz.

#6 Updated by Fuad Saud 7 months ago

Raising doesn't feel like a proper responsability of the exception.
On Sep 15, 2013 3:42 AM, "matz (Yukihiro Matsumoto)" matz@ruby-lang.org
wrote:

Issue #8912 has been updated by matz (Yukihiro Matsumoto).

As Nobu pointed out, we need to use the proper terms:

  • Exception.raise instead of Exception#raise
  • Exception.new instead of Exception#new

We have to distinguish class methods and instance methods.

Then I think we need a way to separate allocating and raising.
By providing Exception.raise (and discouraging Kernel#raise), there's no
sufficient way to raise pre-allocated exceptions.
Kernel raise takes either exception class or exception instance.

If we really need to emphasize OO way in raising exception as you claim,
I'd rather add Exception#raise, i.e.

MyException.new(:foo,:bar).raise

But in reality, I prefer traditional

raise MyException.new(:foo,:bar)

because 'raise' is a core operation, that often is implemented by the
reserved keyword in other languages,
and maybe we will replace it by (somewhat-soft) keyword in the future.

Matz.


Feature #8912: Exception.raise
https://bugs.ruby-lang.org/issues/8912#change-41820

Author: sawa (Tsuyoshi Sawada)
Status: Feedback
Priority: Normal
Assignee:
Category:
Target version:

=begin
When we have a custom exception class with a custom (({initialize}))
method whose arity is not (({1})):

class MyException < StandardError
  def initialize x, y
    super("Something went wrong with #{x.inspect} because #{y}, blah

blah")
end
end

in order to raise it, we have to create a new instance of it explicitly
using (({new})), and embed that under (({Kernel#raise})).

raise(MyException.new(:foo, :bar))

This is inconvenient, and does not look object oriented. I propose that
there should be (({Exception#raise})), which is public, so that we can do:

MyException.raise(:foo, :bar)

A Ruby implementation may be like this:

class Exception
  def self.raise *args; Kernel.send(:raise, *args) end
end

This will disallow us from calling the private method (({Kernel#raise}))
(without an explicit receiver) within the context of an (({Exception}))
class unless we use (({send})), but I think such use case is rare, and that
should not be a problem.
=end

http://bugs.ruby-lang.org/

Also available in: Atom PDF