[Cuis-dev] New updates posted on Github

Gastón Caruso gstn.caruso at gmail.com
Wed Jun 26 14:05:04 PDT 2019


Awesome! thanks for the report! 👏

> On 26 Jun 2019, at 16:04, Juan Vuletich via Cuis-dev <cuis-dev at lists.cuis.st> wrote:
> 
> Hello,
> 
> I had a chance to work on a few things with Andres Valloud, here is his summary of what we just posted on Github.
> 
> First, we turned Complex into a loadable package once more.  Usually the disadvantage is that loading such packages results in code overrides.  For instance, since the message sqrt will have to change behavior (so that -1 sqrt returns a complex number, rather than fail outright), one would expect that loading Complex would have to modify the base system to introduce the new feature.  This time, however, we engineered how Complex interacts with the rest of the system so that loading the Complex package does not result in any base system code modifications.  Of course, loading Complex causes -1 sqrt to evaluate to 0 + 1i, as before.
> 
> The key to accomplishing this was to introduce a new exception, NegativePowerError, which by default comes in without a defaultAction method.  When Complex loads, it simply provides defaultAction so that said exceptions are handled by invoking complex number arithmetic.  We hope this mechanism illustrates one way of making different code packages coexist more harmoniously.  Please include Complex as a requirement to your packages as appropriate.
> 
> Second, and along the same lines, we also found that the arithmetic error exceptions looked very similar and yet their implementation was very different.  Further, there were some discrepancies in how they were used and handled (some would do things like ^ZeroDivide signal..., and some others simply ZeroDivide signal...).  In addition, for floating point numbers, some of the results were not following the IEEE spec.
> 
> As an aside, it seems trivial, but even the following four operations require *substantial* spec lawyering to get right:
> 
> 0.0 - 0.0
> 0.0 - -0.0
> -0.0 - 0.0
> -0.0 - -0.0
> 
> Looks trivial --- it isn't.  And then you consider +, /, and *.  So, we reorganized these exceptions under a general class called ArithmeticMessageError.  This new abstract exception has three instance variables that will look familiar immediately: receiver, message, and arguments.  These are provided by the location where the exception occurs, which in turn allows e.g. defaultAction to resume the computation as required without having to either a) guess what went wrong, or b) needing a multitude of different exceptions depending on what actually happened.  Currently, ArithmeticMessageError has two subclasses for situations that are special enough to deserve their own class: division by zero, and raising a negative number to powers.
> 
> In the "rationals" (i.e. Integer and Fraction), things like 1/0 are undefined. But in floating point land, dividing aFloat by zero can be one of three things (!): +INF, -INF, and NaN.  No, this was not our idea, but we care that things work according to the manual so that our system enables as many folks as possible.  Since floating point requires special handling, there is a ZeroDivide exception to do so.  Something similar happens with NegativePowerError.  In the "rationals", things like -8 raisedTo: 1/3 make sense.  That's because, generally,
> 
> a^(p/q) = (a^p)^1/q
> 
> Note the sign of the result, when it is defined, depends on the sign of a and (essentially) the "parity" of p/q.  Again, this was not our idea, but we gather the world mostly works this way :).
> 
> With floating point numbers, however, it's not obvious what a^b is when a and b are floating point numbers.  Suppose a is negative, and b is 1.0 / 3.0.  Looking at that floating point 1/3, does that mean that if the last bit of the mantissa is zero, that the result does not exist?  And that if the last bit of the mantissa is 1, then it's ok to take something *like* the cubic root of a?  What does that even mean when b is the result of who knows how many operations, each of which is presumably on the order of one ulp off?  Thus, said powers fail, and the result is NaN for floating point numbers.
> 
> If you are curious, consider the fantastic behavior of the following two examples.  Both fail gracefully, as they should.
> 
> -32 raisedTo: (1/5.0) asTrueFraction
> -32 raisedTo: (1/5.0) successor asTrueFraction
> 
> Note that if Complex is loaded, however, a^b will happily work for floating point numbers and produce complex numbers, as expected.  For instance, take G_6.  Since -8 is 8 * w_3, then one of the possible cubic roots is 2 * w_2 (and so is 2 * w_5).
> 
> If this behavior does not work for you, look for the relevant defaultAction method, and also take a look at floatErrorValue.  We tried to make these moldable and easy to change so that people can configure the system to their liking, while requiring minimal modifications.
> 
> Third, all these improvements to exceptions brought up the problem that SUnit was catching errors by handling Error.  This is not ideal because, as just exemplified above, any exception can provide a defaultAction method that recovers its occurrence.  But handling Error like this:
> 
> [3 / 0] on: Error do: [:ex | ex return: 'everybody knows this is bad']
> 
> prevents Error from running its defaultAction, and so a recoverable error always becomes an unrecoverable error.  Instead, the above code should say this:
> 
> [3 / 0] on: UnhandledError do: [:ex | ex return: 'evidently this error was unexpected']
> 
> Consequently, TestResult exError should answer UnhandledError, rather than Error.  We applied this change.  Please consider how you handle exceptions with these observations in mind to maximize flexibility and robustness.
> 
> Andres thinking the above should be at least mostly correct, Juan approving without being too worried.
> 
> -- 
> Cuis-dev mailing list
> Cuis-dev at lists.cuis.st
> https://lists.cuis.st/mailman/listinfo/cuis-dev



More information about the Cuis-dev mailing list