[squeak-dev] a transitive law broken by Fraction since 5.3

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Fri Dec 31 16:50:11 UTC 2021


Hi Chris,
(Fraction numerator: 5 denominator: 1) is an improper Fraction, everything
can happen because it does not fulfill the contract: proper fractions shall
be reduced.
Even if you fix = by reverting to previous version, other things may break.
For example, what happens with:

    [c = a] assert.

Another example:

    | a b |
    a := Fraction numerator: 2 denominator: 10.
    b := Fraction numerator: 3 denominator: 15.
    [a hash = b hash] assert.

Yet another:

    [((Fraction numerator: 2 denominator: 250) nthRoot: 3) = 5 reciprocal]
assert.

Dealing with improper Fraction could be possible, but would involve extra
costs for all sorts of operations.
I advise not to, respecting the invariant enables simpler and efficient
code.
In the same way, you can create Dictionaries that are not properly rehashed
(example when restoring from 32 to 64 bits with too low level constructs).
We can, but shall better not.

Le ven. 31 déc. 2021 à 14:38, Marcel Taeumel <marcel.taeumel at hpi.de> a
écrit :

> One more comment: This used to work by accident before Nicolas actually
> made use of the contract (established in 1999) in Fraction >> #=. Is this
> actually a matter of backwards compatibility?
>
> Best,
> Marcel
>
> Am 31.12.2021 14:33:36 schrieb Marcel Taeumel <marcel.taeumel at hpi.de>:
> Ha! Reading the comment in #numerator:denominator:, this isn't really a
> bug but an inconvenience:
>
> NOTE: This primitive initialization method will not reduce improper
> fractions,
> so normal usage should be coded as, eg,
> (Fraction numerator: a denominator: b) reduced
> or, more simply, as
> a / b
>
> -- di 8/31/1999
>
> :-)
>
> No transitive law broken here. Not sure how we can avoid using
> #numerator:denominator: without #reduced ... sounds like a linting rule to
> enforce ...
>
> Best,
> Marcel
>
> Am 31.12.2021 14:30:39 schrieb Marcel Taeumel <marcel.taeumel at hpi.de>:
> Hi Chris --
>
> > Fraction numerator: 5 denominator: 1.
>
> I think that the issue is that this line does not answer an Integer but a
> Fraction. Numbers are special in the object-oriented world in that they can
> change their class without notice. :-)
>
> This works:
>
> | a b c |
> a := 5/1.
> b := 5.0.
> c := 5.
> self assert: a=b; assert: b=c.   "Pass"
> self assert: a=c.    "Fail"
>
> Best,
> Marcel
>
> Am 31.12.2021 01:30:25 schrieb Chris Muller <ma.chris.m at gmail.com>:
> __________
> *“If a is equal to b and b is equal to c, then a is equal to c.”*
> __________
>
> | a b c |
> a := Fraction numerator: 5 denominator: 1.
> b := 5.0.
> c := 5.
> self assert: a=b; assert: b=c.   "Pass"
> self assert: a=c.    "Fail"
> __________
>
> I understand this is not a normal way to create Fractions, but serializers
> must often construct objects in other-than-normal ways.  This constructor
> on Fraction is actually a valid API, but leaves an inconsistent comparison
> contract with other Numbers.
>
> I fixed it by reverting Fraction>>#= to the (nice 3/28/2006 23:41) edition.
>
> Comments?
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20211231/af78a69b/attachment.html>


More information about the Squeak-dev mailing list