What's the suggested raise Exception idiom?

What's the distinction between:
   raise ArgumentError, "the argument was invalid"
and
  raise ArgumentError.new("the argument was invalid")

How does this apply in the case of exceptions with custom initializers
for attributes? For example:
  class StatusCodeError < StandardError
      attr_reader :status_code
      def initialize(status_code)
          @status_code = status_code
      end
  end

I've been reading a lot of code, books and blogs, but haven't gotten
as clear of an understanding on why people choose one way over
another, so I'm looking for additional opinions and commentary.

Thanks

I believe raise a,b,c,d... is merely syntactig sugar for raise a.new(b,c,d...) with a bit of added functionality (e.g. if a is not an exception class there is an error, if a is a String a StandardError is raised).

To answer your question, normally there is no reason to use a variant with "new" - rather save yourself a bit of typing and use the shorter form. My 0.02EUR.

Kind regards

  robert

···

On 03/23/2010 06:22 PM, Nathan Beyer wrote:

What's the distinction between:
   raise ArgumentError, "the argument was invalid"
and
  raise ArgumentError.new("the argument was invalid")

How does this apply in the case of exceptions with custom initializers
for attributes? For example:
  class StatusCodeError < StandardError
      attr_reader :status_code
      def initialize(status_code)
          @status_code = status_code
      end
  end

I've been reading a lot of code, books and blogs, but haven't gotten
as clear of an understanding on why people choose one way over
another, so I'm looking for additional opinions and commentary.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Not exactly so. According to the passage from RI below, "raise" with an exception class as a first paremeter accepts up to 2 additional parameters -- the first one will be used as an argument to new when the exception object is instantiated, and the second, if any, must be an array representing callback information.

When I need an exception class with more than one argument, I use something like the following:

class DimensionError < RuntimeError
  attr_reader :width, :hight
  def initialize(*args)
    @width, @hight = *args
    super "Wrong dimension #{width}x#{hight}"
  end
end

begin
  raise DimensionError, [ 5, 3 ]
rescue DimensionError => error
  error.wigth
  error.length
end

= OR =

class DimensionError < RuntimeError
  attr_reader :width, :hight
  def initialize(options = {})
    @width = options[:width]
    @hight = options[:hight]
    super "Wrong dimension #{width}x#{hight}"
  end
end

begin
  raise DimensionError, :width => 5, :hight => 3
rescue DimensionError => error
  error.wigth
  error.length
end

----------------------------------------------------------- Kernel#raise
     raise
     raise(string)
     raise(exception [, string [, array]])
     fail
     fail(string)
     fail(exception [, string [, array]])

···

On Mar 23, 2010, at 2:45 PM, Robert Klemme wrote:

On 03/23/2010 06:22 PM, Nathan Beyer wrote:

What's the distinction between:
  raise ArgumentError, "the argument was invalid"
and
raise ArgumentError.new("the argument was invalid")

How does this apply in the case of exceptions with custom initializers
for attributes? For example:
class StatusCodeError < StandardError
     attr_reader :status_code
     def initialize(status_code)
         @status_code = status_code
     end
end

I've been reading a lot of code, books and blogs, but haven't gotten
as clear of an understanding on why people choose one way over
another, so I'm looking for additional opinions and commentary.

I believe raise a,b,c,d... is merely syntactig sugar for raise
a.new(b,c,d...) with a bit of added functionality (e.g. if a is not an
exception class there is an error, if a is a String a StandardError is
raised).

------------------------------------------------------------------------
     With no arguments, raises the exception in $! or raises a
     RuntimeError if $! is nil. With a single String argument, raises a
     RuntimeError with the string as a message. Otherwise, the first
     parameter should be the name of an Exception class (or an object
     that returns an Exception object when sent an exception message).
     The optional second parameter sets the message associated with the
     exception, and the third parameter is an array of callback
     information. Exceptions are caught by the rescue clause of
     begin...end blocks.

        raise "Failed to create socket"
        raise ArgumentError, "No parameters", caller

To answer your question, normally there is no reason to use a variant
with "new" - rather save yourself a bit of typing and use the shorter
form. My 0.02EUR.

Kind regards

  robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

I believe raise a,b,c,d... is merely syntactig sugar for raise
a.new(b,c,d...) with a bit of added functionality (e.g. if a is not an
exception class there is an error, if a is a String a StandardError is
raised).

Not exactly so. According to the passage from RI below, "raise" with an exception class as a first paremeter accepts up to 2 additional parameters -- the first one will be used as an argument to new when the exception object is instantiated, and the second, if any, must be an array representing callback information.

Right you are. Thanks for the education! Apparently I never had the
need for this. :slight_smile:

When I need an exception class with more than one argument, I use something like the following:

class DimensionError < RuntimeError
attr_reader :width, :hight
def initialize(*args)
@width, @hight = *args
super "Wrong dimension #{width}x#{hight}"
end
end

begin
raise DimensionError, [ 5, 3 ]
rescue DimensionError => error
error.wigth
error.length
end

That does not seem to work as you expect on 1.9:

irb(main):038:0> class E1 < Exception
irb(main):039:1> def initialize(*a) p a end
irb(main):040:1> end
=> nil
irb(main):041:0> begin; raise E1,[1,2]; rescue Exception => e; p e; end
[[1, 2]]
#<E1: E1>
=> #<E1: E1>
irb(main):042:0> class E1 < Exception
irb(main):043:1> def initialize(*a) x,y=*a; p x,y end
irb(main):044:1> end
=> nil
irb(main):045:0> begin; raise E1,[1,2]; rescue Exception => e; p e; end
[1, 2]
nil
#<E1: E1>
=> #<E1: E1>
irb(main):046:0> RUBY_VERSION
=> "1.9.1"

You would have to do

irb(main):047:0> class E1 < Exception
irb(main):048:1> def initialize(a) x,y=*a; p x,y end
irb(main):049:1> end
=> nil
irb(main):050:0> begin; raise E1,[1,2]; rescue Exception => e; p e; end
1
2
#<E1: E1>
=> #<E1: E1>
irb(main):051:0>

Note the missing splash operator in initialize's argument list.

Kind regards

robert

···

2010/3/24 Gennady Bystritsky <Gennady.Bystritsky@quest.com>:

On Mar 23, 2010, at 2:45 PM, Robert Klemme wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Well, I am still on 1.8.6, missed the issue on 1.9.x ;-). Thanks for pointing this out. Besides, an exception's initialize() accepts only one parameter anyway, so your no-splash version should work for 1.8.x as well. I started using Hash-based initialize() recently, and it seems to work same way both in 1.8 and 1.9.

Gennady.

···

On Mar 24, 2010, at 1:31 AM, Robert Klemme wrote:

2010/3/24 Gennady Bystritsky <Gennady.Bystritsky@quest.com>:

On Mar 23, 2010, at 2:45 PM, Robert Klemme wrote:

I believe raise a,b,c,d... is merely syntactig sugar for raise
a.new(b,c,d...) with a bit of added functionality (e.g. if a is not an
exception class there is an error, if a is a String a StandardError is
raised).

Not exactly so. According to the passage from RI below, "raise" with an exception class as a first paremeter accepts up to 2 additional parameters -- the first one will be used as an argument to new when the exception object is instantiated, and the second, if any, must be an array representing callback information.

Right you are. Thanks for the education! Apparently I never had the
need for this. :slight_smile:

When I need an exception class with more than one argument, I use something like the following:

class DimensionError < RuntimeError
attr_reader :width, :hight
def initialize(*args)
   @width, @hight = *args
   super "Wrong dimension #{width}x#{hight}"
end
end

begin
raise DimensionError, [ 5, 3 ]
rescue DimensionError => error
error.wigth
error.length
end

That does not seem to work as you expect on 1.9:

irb(main):038:0> class E1 < Exception
irb(main):039:1> def initialize(*a) p a end
irb(main):040:1> end
=> nil
irb(main):041:0> begin; raise E1,[1,2]; rescue Exception => e; p e; end
[[1, 2]]
#<E1: E1>
=> #<E1: E1>
irb(main):042:0> class E1 < Exception
irb(main):043:1> def initialize(*a) x,y=*a; p x,y end
irb(main):044:1> end
=> nil
irb(main):045:0> begin; raise E1,[1,2]; rescue Exception => e; p e; end
[1, 2]
nil
#<E1: E1>
=> #<E1: E1>
irb(main):046:0> RUBY_VERSION
=> "1.9.1"

You would have to do

irb(main):047:0> class E1 < Exception
irb(main):048:1> def initialize(a) x,y=*a; p x,y end
irb(main):049:1> end
=> nil
irb(main):050:0> begin; raise E1,[1,2]; rescue Exception => e; p e; end
1
2
#<E1: E1>
=> #<E1: E1>
irb(main):051:0>

Note the missing splash operator in initialize's argument list.