Ray Toal Ray Toal - 1 month ago 8
Ruby Question

Custom fields in a Ruby exception object not shown when inspecting

If I create a class in Ruby, I can generally "see" its fields when using

inspect
:

>> class C; def initialize; @x=1; end; end
=> :initialize
>> C.new.inspect
=> "#<C:0x007fd5b9119c20 @x=1>"


This does not seem to hold true for exceptions:

>> class E < StandardError; def initialize; super("hello"); @y=2; end; end
=> :initialize
>> begin; raise E.new; rescue E => e; puts e.inspect; end
#<E: hello>
=> nil


I would have expected this to show
#<E: hello @y=2>
! So naturally I went to the documentation and saw that the
Error
class specifically overrides
inspect
to "return this exception’s class name and message."

This leads me to believe that either (1) adding extra descriptive fields to an error object is a bad thing, or (2) the author of the Ruby
Error
class made a mistake, or (3) there is something inherently weird about error objects that an explicit override of
inspect
was needed!

I don't mean for this to be an opinion question. My programming question here is:


  • If the answer is (1), and it is bad practice to add fields to an error object, what should I do instead?

  • If the answer is (2), how does one get around this mess? Override
    inspect
    in one's custom error subclass?


Answer

If the answer is (2), how does one get around this mess? Override inspect in one's custom error subclass?

I do not know why would you want to have instance variables in error class, but if

how does one get around this mess?

means

where are the instance variables I have defined for the object?

the answer is as follows:

begin; raise E.new; rescue E => e; puts e.instance_variables; end
#=> @y

To have instance variables shown within inspect you will for sure have to override inspect method:

class E < StandardError
  def initialize
    super('hello')
    @y = 2
  end

  def inspect
    "<#{self.class}: #{message}, #{instance_variables.map { |v| "#{v}=#{instance_variable_get(v)}"}.join(', ')}>"
  end
end
begin; raise E.new; rescue E => e; puts e.inspect; end
#=> <E: hello, @y=2>

I do not see any mess here :)

Comments