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. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20071211/0ce0f0c4/attachment-0001.html -------------- next part -------------- A non-text attachment was scrubbed... Name: FixnumMethods.patch Type: application/octet-stream Size: 243956 bytes Desc: not available Url : http://rubyforge.org/pipermail/ironruby-core/attachments/20071211/0ce0f0c4/attachment-0001.obj
Peter Bacon Darwin:> 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 Darwin <bacondarwin at googlemail.com> 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 .
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 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20071212/2cfee3b9/attachment.html
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<int> 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 Darwin <bacondarwin at googlemail.com> wrote:> > > > > 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 > _______________________________________________ > Ironruby-core mailing list > Ironruby-core at rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core > >-- Brian J. Cardiff bcardiff(?)gmail.com .
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<int> 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<int> 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 :-) ) - John
John Messerly:> Definitely a good thing to do--as long as we actually handle > Nullable<int> 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<int>, 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
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 -----Original Message----- From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of John Messerly Sent: Wednesday,12 December 12, 2007 21:08 To: ironruby-core at rubyforge.org Subject: Re: [Ironruby-core] Fixnum Patch 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<int> 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<int> 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 :-) ) - John _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core
Peter Bacon Darwin:> 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 :) - John
Peter Bacon Darwin:> 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<int>. As Dino & Tomas pointed out, now we''re playing games with our type system, because to the CLR Int32 and Nullable<Int32> are different types. For example, if you have a CLR method "foo" that returns Nullable<Int32>: x = obj.foo # x is now a Nullable<Int32> 5 + x # this is probably okay; the method binder converts Nullable<Int32> arguments to Int32 x + 5 # how does this work? Nullable<T> doesn''t define the Ruby method "+" Since x is a Nullable<Int32>, we should be looking up method calls on Nullable<Int32>. 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
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<Int32> 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 Messerly wrote:>> On second thought, it might be better to not use Nullable<int>. As Dino &Tomas pointed out, now we''re playing games with our>> type system, because to the CLR Int32 and Nullable<Int32> are differenttypes. For example, if you have a CLR method "foo" that>> returns Nullable<Int32>: >> >> x = obj.foo # x is now a Nullable<Int32> >> 5 + x # this is probably okay; the method binder convertsNullable<Int32> arguments to Int32>> x + 5 # how does this work? Nullable<T> doesn''t define the Rubymethod "+">> >> Since x is a Nullable<Int32>, we should be looking up method calls onNullable<Int32>. But that won''t work...>> >> Actually, it might be a bug that it''s working now. Probably better tojust leave return values as "object".>> >> - John
Peter Bacon Darwin:> As it turns out, since there is loads of boxing going on in > IronRuby/DLR you do actually get the right semantics for free. > > <snip>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