Fixnum Patch

Overview:

The focus of this patch is to implement the Fixnum methods and to
provide
RSpec tests for those methods. In addition the Bignum methods have been
tweaked and the tests for Bignum have been improved by adding more edge
cases. The implementation of the Fixnum methods required some methods
in
other classes to be added or modified. These have not been tested to
the
same level as the Fixnum and Bignum methods and there may be edge cases
that
have been missed.

To help with running the tests I added a small script, run_builtin.rb
that
lets you run all the tests for a particular builtin class (such as
Fixnum)
on both ruby.exe and rbx.exe side by side. I found this particularly
useful
when writing and testing the specs to see where the work was. Usage is
as
follows: ruby run_builtin.rb {BuiltinType}, where {BuiltinType} is the
name
of a folder below the BuiltIn folder containing the specs to run. It
assumes that you are running it from the trunk/tests/ironruby folder and
that ruby.exe is in the path. E.g. ruby run_builtin.rb Fixnum.

Of course, bear in mind that until Bignum gets “switched on” none of the
Bignum related functionality will work.

Code Change Detail:

BignumOps.cs

. This file has had a general tidy up. The methods have been
reordered and group better.

. The CoerceAndCall method has been moved to Numeric.

. All exceptions are now created via Ruby.Runtime.RubyExceptions

. A number of methods, notably BignumOps.Compare, now return an
object rather than a Float (int). This is because these methods
sometimes
are expected to return nil (null).

Comparable.cs

. The major change here is that Protocols.Compare is no longer
assumed to return a bool and we first test for null before casting the
result to an int.

FloatOps.cs

. Added a number of methods to support the post-coercion calling
from Bignum and Fixnum. These methods are not expected to deal with all
cases yet. Methods affected include: ceil, floor, to_i, to_int,
truncate,
to_f and round.

. Methods such as <=>, < and divmod have had additional checks
put
in place to deal with unusual cases of Infinity and NaN. Possibly
these
will be moved into the Protocols classes in due course?

Integer.cs

. Added the “integer?” method.

Numeric.cs

. Implemented all the Numeric instance methods. These have not
been
subject to rigorous unit testing yet.

. Implemented a number of helper methods, used by the other
Numeric
classes such as Bignum and Fixnum: CoerceAndCall, CoerceAndCallCompare,
CoerceAndCallRelationOperator, MakeCoercionError and
MakeComparisonError.

. Also added the singleton_method_added method. But currently
this
does not get called as it has not yet been defined in Object (Kernel).

NumericSites.cs

. Added a number of additional sites to support the Numeric
classes.

. The NumericSites.Coerce method now does some additional checks
on
what is returned from the invocation.

ObjectOps.cs

. Added inspect and new methods. These help creating the
fixtures
for the Fixnum and Bignum tests.

SymbolOps.cs

. Fixed ToString to return null if the symbol does not exist in
the
SymbolTable.

. Fixed Inspect accordingly.

Peter Bacon D.:

Subject: [Ironruby-core] Fixnum Patch

Overview:

Thanks for sending in this patch, Peter! We’ll review and integrate
ASAP.

We’ll do the fixes in Protocols to get the tests to pass as well.

-John

On Dec 11, 2007 12:19 PM, Peter Bacon D.
[email protected] wrote:

· A number of methods, notably BignumOps.Compare, now return an
object rather than a Float (int). This is because these methods sometimes
are expected to return nil (null).

wouldn’t be better to use nullable types? So, for example, it would be
clear that the result is either null or int, and there is not
propagation of casts.


Brian J. Cardiff
bcardiff(?)gmail.com
.

I agree in the pros of using nullable: Clarity and Performance.

Also my previous mail was inspired in what your original need: returns
int or null, so using Nullable it seems to be the smallest
solution. But I didn’t have in mind if there are some issues in
exposing them to the ruby engine.

On Dec 12, 2007 11:56 AM, Peter Bacon D.
[email protected] wrote:

propagation of casts.
confident in using them in library code (how often do you actually see them

public int? Compare(BigInteger self, BigInteger other)

leads to code like


Brian J. Cardiff
bcardiff(?)gmail.com
.

Brian J. Cardiff wrote:

wouldn’t be better to use nullable types? So, for example, it would be

clear that the result is either null or int, and there is not

propagation of casts.

This is a fair comment and one that I did consider.

I am generally a bit weary of Nullable types and I didn’t feel overly
confident in using them in library code (how often do you actually see
them
used in practice?). This is no excuse of course.

The two reasons in favour of using NullableTypes as I see them are
clarity
and performance.

Clarity

Ruby doesn’t really appear to care much about the return type on the
method
itself; it is more interested in the object that is returned; and so the
user of the class (in Ruby) won’t be able to tell the difference anyway.
There are other cases where object is returned regularly

In fact almost all the Bignum methods return object since the result may
well be converted to a Fixnum (if it is small enough) or even a Float
(if
the result is not supposed to be Integer).

Performance

In the end there is not much gained in using more specific types in
these
cases. The only reason would be for performance (saving the cost of
Boxing
or casting) but to get to the value of a Nullable type you still have to
check whether it is null and then access the Value property anyway so
there
is probably not much in it.

public int? Compare(BigInteger self, BigInteger other)

leads to code like

int? result = Compare(someBigInt, otherBigInt);

if (result.HasValue) {

  int actualResult = result.Value

  // Do something with it

} else {

  // Do something with null

}

public object Compare(BigInteger self, BigInteger other)

leads to code like

object result = Compare(someBigInt, otherBigInt);

if (result is int) {

  int actualResult = (int)result;

  // Do something with it

} else {

  // Do something with null

}

The main reason I kept away from using them, was that it keeps the
options
open and is more in keeping with the general style of the library code.

Am I barking up the wrong tree here? I may well be missing something.
Let
me know what you think.

Pete

John M.:

Definitely a good thing to do–as long as we actually handle
Nullable correctly. Off the top of my head I’m not sure. Worth
trying though.

Oh, and just to be clear, what I mean is if you try to examine the
resulting object, does the resulting object show up as a real
Fixnum/NilClass? I’m afraid it might come through as an instance of
Nullable, which wouldn’t be right. If it does, work we need to fix
it, but the workaround for now would be to return an object.

  • John

Brian J. Cardiff wrote:

I agree in the pros of using nullable: Clarity and Performance.

Also my previous mail was inspired in what your original need: returns
int or null, so using Nullable it seems to be the smallest
solution. But I didn’t have in mind if there are some issues in
exposing them to the ruby engine.

Definitely a good thing to do–as long as we actually handle
Nullable correctly. Off the top of my head I’m not sure. Worth
trying though.

For better or worse, there are a lot of methods that need to have their
return types typed to System.Object. Methods that take blocks usually
need to return object (in case the block breaks with an arbitrary
object, which we need to pass through). Also if you’re calling back
through a dynamic site into Ruby code, even if the method should
normally return a particular type (for example, <=> is supposed to
return Fixnum +1, 0, or -1), nothing stops the user from returning
whatever they want. We actually don’t get this right today in several
places.

(Ah, the fun of implementing a dynamically typed language in a
statically typed one :slight_smile: )

  • John

What John discusses below was part of the reason I was wary (not weary!)
of
using Nullable types.

I have now tested it and if you have a method that, for instance,
returns
int? then on the occasions that null is returned that class of the
resulting
object is NilClass and when it is not null, the class is Fixnum. So all
seems to be well and I am happy to fix-up those methods in Bignum and
Fixnum
that should use Nullable types when I next submit a patch.

Thanks for pointing this out.
Pete

Peter Bacon D.:

I have now tested it and if you have a method that, for instance,
returns int? then on the occasions that null is returned that class of
the resulting object is NilClass and when it is not null, the class is
Fixnum. So all seems to be well and I am happy to fix-up those methods
in Bignum and Fixnum that should use Nullable types when I next submit
a patch.

I love it when stuff just works :slight_smile:

  • John

As it turns out, since there is loads of boxing going on in IronRuby/DLR
you
do actually get the right semantics for free.

When a nullable value type is boxed you either get a null reference or a
boxed version of the underlying value type. Great! This means that,
since
all dynamic invocations go via methods that look like this (note the
“object” return type):

public override object Invoke(object arg0) { return _target(arg0 !=
null ? (T0)arg0 : default(T0)); }

The nullable type gets converted into a regular null or boxed value
type.
You can see this happen if you step through the code. It is a bit
creepy
actually. The DLR knows that the return type of a method is actually a
Nullable but the actual value is either a null or Int32.

The example given below, therefore, does actually do what you want it
to.
The value of x actually is a Fixnum and so works like a treat.

This is still all a bit scary and I personally think keeping object
rather
than int? is safer and doesn’t detract from the clarity. Also, since
there
is all this boxing going on anyway you get no performance benefit
either.

Pete

John M. wrote:

On second thought, it might be better to not use Nullable. As Dino &
Tomas pointed out, now we’re playing games with our

type system, because to the CLR Int32 and Nullable are different
types. For example, if you have a CLR method “foo” that

returns Nullable:

x = obj.foo # x is now a Nullable
5 + x # this is probably okay; the method binder converts
Nullable arguments to Int32

x + 5 # how does this work? Nullable doesn’t define the Ruby
method “+”

Since x is a Nullable, we should be looking up method calls on
Nullable. But that won’t work…

Actually, it might be a bug that it’s working now. Probably better to
just leave return values as “object”.

Peter Bacon D.:

As it turns out, since there is loads of boxing going on in
IronRuby/DLR you do actually get the right semantics for free.

Nice job tracking that one down. Makes a lot more sense now.

This is still all a bit scary and I personally think keeping object
rather than int? is safer and doesn’t detract from the clarity. Also,
since there is all this boxing going on anyway you get no performance
benefit either.

Agreed. I think it’s safe to say the current behavior is an
implementation side effect, not something to be relied on at this point.

  • John

Peter Bacon D.:

What John discusses below was part of the reason I was wary (not
weary!) of using Nullable types.

I have now tested it and if you have a method that, for instance,
returns int? then on the occasions that null is returned that class of
the resulting object is NilClass and when it is not null, the class is
Fixnum. So all seems to be well and I am happy to fix-up those methods
in Bignum and Fixnum that should use Nullable types when I next submit
a patch.

On second thought, it might be better to not use Nullable. As Dino
& Tomas pointed out, now we’re playing games with our type system,
because to the CLR Int32 and Nullable are different types. For
example, if you have a CLR method “foo” that returns Nullable:

x = obj.foo # x is now a Nullable
5 + x # this is probably okay; the method binder converts
Nullable arguments to Int32
x + 5 # how does this work? Nullable doesn’t define the Ruby
method “+”

Since x is a Nullable, we should be looking up method calls on
Nullable. But that won’t work…

Actually, it might be a bug that it’s working now. Probably better to
just leave return values as “object”.

  • John

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs