Raising Exceptions

Just a quick question about raising exceptions in IronRuby libraries.
Should we just simply throw a new CLR exception or do we need to use the
ExceptionOps stuff when creating exceptions.

As an example, in FloatOps, I have a method for divmod:

    [RubyMethod("divmod")]

    public static RubyArray DivMod(double self, double other) {

        // Unlike modulo, divmod throws an error if the quotient is 

not
a proper number.

        // This appears to be an inconsistency in MRI.

        double quotient = self / other;

        if (Double.IsNaN(quotient) || Double.IsInfinity(quotient) ) 

{

            throw new FloatDomainError("NaN");

        }

        return InternalDivMod(self, other);

    }

If the quotient is not valid then we raise a FloatDomainError. The
FloatDomainError class uses ExceptionOps.MakeMessage and also
ExceptionOps.InitializeException in the constructor. A quick look at
InitializeException puts some data into the Exception.Data property,
which I
am assuming, without going any deeper, is required by the Ruby runtime
to
handle the exception correctly.

This is all well and good, but when you look at BignumOps, I have a
method
for to_s:

    [RubyMethod("to_s")]

    public static object ToString(BigInteger self, uint radix) {

        try {

            // TODO: Can we do the ToLower in BigInteger?

            return new 

MutableString(self.ToString(radix).ToLower());

        } catch (ArgumentOutOfRangeException x) {

            throw ArgumentErrorOps.Factory(new

MutableString(x.Message));

        }

    }

Now this one needs to raise an ArgumentError, which is actually a Ruby
wrapper around System.ArgumentException (i.e. ArgumentError is a pure
Ruby
class that “extends” the CLR class System.ArgumentException. Now I
could
have just created a new ArgumentException here but since this doesn’t
call,
apart from anything else, ExceptionOps.InitializeException, I felt I
needed
to use the ArgumentErrorOps.Factory method to create the exception. I
believe the primary reason for this method is so that the DLR can create
exceptions from pure Ruby code, i.e. raise ArgumentError, …

Am I being over-cautious here and should I be happily creating CLR
exceptions directly and not worrying too much? I expect and hope that
this
is the case, as otherwise how would the DLR deal with cases where pure
.NET
classes throw pure CLR exceptions?

Cheers,

Pete

Our automatic exception mapping mechanism maps
ArgumentOutOfRangeExceptions to RangeErrors. Since the correct behavior
in this case appears to be raising an ArgumentError, it makes sense to
catch and rethrow.

I’m attaching a PDF that shows how we map CLR exceptions to Ruby
exceptions.

Thanks,
-John

From: [email protected]
[mailto:[email protected]] On Behalf Of Peter Bacon
Darwin
Sent: Thursday, December 06, 2007 2:40 AM
To: [email protected]
Subject: [Ironruby-core] Raising Exceptions

Just a quick question about raising exceptions in IronRuby libraries.
Should we just simply throw a new CLR exception or do we need to use the
ExceptionOps stuff when creating exceptions.
As an example, in FloatOps, I have a method for divmod:

    [RubyMethod("divmod")]
    public static RubyArray DivMod(double self, double other) {
        // Unlike modulo, divmod throws an error if the quotient is 

not a proper number.
// This appears to be an inconsistency in MRI.
double quotient = self / other;
if (Double.IsNaN(quotient) || Double.IsInfinity(quotient) )
{
throw new FloatDomainError(“NaN”);
}
return InternalDivMod(self, other);
}

If the quotient is not valid then we raise a FloatDomainError. The
FloatDomainError class uses ExceptionOps.MakeMessage and also
ExceptionOps.InitializeException in the constructor. A quick look at
InitializeException puts some data into the Exception.Data property,
which I am assuming, without going any deeper, is required by the Ruby
runtime to handle the exception correctly.

This is all well and good, but when you look at BignumOps, I have a
method for to_s:

    [RubyMethod("to_s")]
    public static object ToString(BigInteger self, uint radix) {
        try {
            // TODO: Can we do the ToLower in BigInteger?
            return new 

MutableString(self.ToString(radix).ToLower());
} catch (ArgumentOutOfRangeException x) {
throw ArgumentErrorOps.Factory(new
MutableString(x.Message));
}
}

Now this one needs to raise an ArgumentError, which is actually a Ruby
wrapper around System.ArgumentException (i.e. ArgumentError is a pure
Ruby class that “extends” the CLR class System.ArgumentException. Now I
could have just created a new ArgumentException here but since this
doesn’t call, apart from anything else,
ExceptionOps.InitializeException, I felt I needed to use the
ArgumentErrorOps.Factory method to create the exception. I believe the
primary reason for this method is so that the DLR can create exceptions
from pure Ruby code, i.e. raise ArgumentError, …

Am I being over-cautious here and should I be happily creating CLR
exceptions directly and not worrying too much? I expect and hope that
this is the case, as otherwise how would the DLR deal with cases where
pure .NET classes throw pure CLR exceptions?

Cheers,
Pete

John L. (DLR):

I’m attaching a PDF that shows how we map CLR exceptions to Ruby
exceptions.

I guess the ! means “not equivalent” and “skip parent” means we change
the base class mapping but otherwise map it?

(Also the bottom of the PDF appears cut off.)

  • John