Float Generality / Coercion

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Float Generality / Coercion

Ken Treis
I'm porting Travis Griggs' "Measurements" package from VisualWorks to GemStone and hit a snag with number generality. I think I've got a workable solution but wanted to run it by have it reviewed by people smarter than I am; and, barring any objections, I'm lobbying for it to be included in the base.

The basic gist is that Floats assume that they're the top of the generality food chain, so when (say) the multiplication primitive fails, they don't bother trying to coerce their peers using the normal means. I'm proposing changing methods like this (in 3.1.0.1):

Float>>* aNumber
"Multiply the receiver by aNumber and returns the result."
<primitive: 102>
aNumber _isNumber ifFalse:[ aNumber _validateClass: Number ].
^ self * aNumber asFloat

to something like:

Float>>* aNumber
"Multiply the receiver by aNumber and returns the result."
<primitive: 102>
^self _retry: #* coercing: aNumber

This would allow introduction of objects that are not Numbers (strictly speaking) but could still participate in arithmetic operations with numbers. VisualWorks implements non-numeric "ArithmeticValues" this way, so coercion works with Points, Complex numbers, etc. Points have a generality of 160, Complex is 150.

The Measurements package introduces an object like this; it's a number with a unit attached (3.0e8 ~> 'm/s'). When multiplying by a float, we want the float to be coerced to a Measurement.

I'm assuming that the primitive can handle most or all of the built-in Number classes natively, so the only change to the overall efficiency here (if any) would be in edge cases like the one I'm trying to introduce here.

Compared to the original code, the coercing method will still do the right thing for numbers that the primitive might not know how to handle, provided those Number classes implement _generality and #asFloat. And it'll still throw an error (MNU: _generality) if you try to multiply by an object that doesn't understand enough Number protocol. 

Anything I'm missing? I've implemented this in a scratch repository for multiplication and division and everything is working fine.

GLASS note: in order to make Point math work, I had to implement _generality and _coerce: there as well. That actually cleared up an unrelated problem in Point arithmetic. In a stock GLASS install:

(1@2)* 2 => (2@4)
(1@2)* 2.0 => (2.0@4.0)
2 * (1@2) => MNU: _generality
2.0 * (1@2) => rtErrBadArgKind: expected Number

.. but this change cleans it up.

--
Ken Treis
Miriam Technologies, Inc.
(866) 652-2040 x221

Reply | Threaded
Open this post in threaded view
|

Re: [GemStone-Smalltalk] Float Generality / Coercion

Allen Otis
The base image for 3.1.0.2 already includes your proposed
change to methods in Float .

Allen Otis
VMware

On 11/13/2012 05:57 PM, Ken Treis wrote:

> I'm porting Travis Griggs' "Measurements" package from VisualWorks to GemStone and hit a snag with number generality. I
> think I've got a workable solution but wanted to run it by have it reviewed by people smarter than I am; and, barring
> any objections, I'm lobbying for it to be included in the base.
>
> The basic gist is that Floats assume that they're the top of the generality food chain, so when (say) the multiplication
> primitive fails, they don't bother trying to coerce their peers using the normal means. I'm proposing changing methods
> like this (in 3.1.0.1):
>
>> *Float>>* aNumber*
>> "Multiply the receiver by aNumber and returns the result."
>> <primitive: 102>
>> aNumber _isNumber ifFalse:[ aNumber _validateClass: Number ].
>> ^ self * aNumber asFloat
>
> to something like:
>
>> *Float>>* aNumber*
>> "Multiply the receiver by aNumber and returns the result."
>> <primitive: 102>
>> ^self _retry: #* coercing: aNumber
>
> This would allow introduction of objects that are not Numbers (strictly speaking) but could still participate in
> arithmetic operations with numbers. VisualWorks implements non-numeric "ArithmeticValues" this way, so coercion works
> with Points, Complex numbers, etc. Points have a generality of 160, Complex is 150.
>
> The Measurements package introduces an object like this; it's a number with a unit attached (3.0e8 ~> 'm/s'). When
> multiplying by a float, we want the float to be coerced to a Measurement.
>
> I'm assuming that the primitive can handle most or all of the built-in Number classes natively, so the only change to
> the overall efficiency here (if any) would be in edge cases like the one I'm trying to introduce here.
>
> Compared to the original code, the coercing method will still do the right thing for numbers that the primitive might
> not know how to handle, provided those Number classes implement _generality and #asFloat. And it'll still throw an error
> (MNU: _generality) if you try to multiply by an object that doesn't understand enough Number protocol.
>
> Anything I'm missing? I've implemented this in a scratch repository for multiplication and division and everything is
> working fine.
>
> GLASS note: in order to make Point math work, I had to implement _generality and _coerce: there as well. That actually
> cleared up an unrelated problem in Point arithmetic. In a stock GLASS install:
>
> (1@2)* 2 => (2@4)
> (1@2)* 2.0 => (2.0@4.0)
> 2 * (1@2) => MNU: _generality
> 2.0 * (1@2) => rtErrBadArgKind: expected Number
>
> .. but this change cleans it up.
>
> --
> Ken Treis
> Miriam Technologies, Inc.
> (866) 652-2040 x221
>
>
>
> _______________________________________________
> GemStone-Smalltalk mailing list
> Archive: http://forum.world.st/Gemstone-Customers-f1461796.html
>