chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] fixnum-specific math operators patch


From: Will M Farr
Subject: Re: [Chicken-users] fixnum-specific math operators patch
Date: Fri, 1 Sep 2006 10:15:52 -0400

Hello all,

On Sep 1, 2006, at 3:06 AM, Kon Lovett wrote:

I think the fx* shouldn't check their arguments, ever. While the safe/unsafe rational makes sense (nicely symmetric), people shouldn't use these routines if not 100% sure of the types. The goes for the (fixnum arithmetic) declaration.

This is what I thought until yesterday, too. But then I realized what people who want both safety against careless users and speed have to do to achieve these goals. Allow me to illustrate with one of my favorite macros :) :

(define-syntax do-range
  (syntax-rules ()
    ((_ (i aa bb) expr ...)
     (let ((a aa)
           (b bb))
       (do ((i a (fx+ i 1)))
           ((fx= i b))
         expr ...)))))

As written this macro will go nuts if someone calls it with a float- producing expression for aa or bb:

(let ((the-rev-indices '()))
  (do-range (i 0.0 (vector-length v))
    (set! the-rev-indices (cons i the-rev-indices)))
  ... (use the-rev-indices) ...)

This will generate an error in safe mode, but *not until the (use the- rev-indices) form is evaluated*. That can be well past the use of the do-range macro, and is therefore very hard to debug. I can see three possibilities for fixing this:

1. Tell the user to never pass a non-fixnum expression to do-range (and force them to require this of all library code they might use to determine the range arguments of the macro). If they fail to respect this requirement, their program will fail with a strange error message when they use the invalid value of i. This is clearly not The Right Thing (TM).

2. Re-define the macro to

(define-syntax do-range
  (syntax-rules ()
    ((_ (i aa bb) expr ...)
     (let ((a aa)
           (b bb))
       (if (or (not (fixnum? a))
               (not (fixnum? b)))
           (error 'do-range "non-fixnum limits" a b)
           (do ((i a (fx+ i 1)))
               ((fx= i b))
             expr ...))))))

Now the user doesn't get a cryptic error when he/she calls do-range with strange arguments. The macro throws a sensible error before entering the loop---the error is associated with the point at which the mistake was made. BUT, if the user declares (unsafe)---that is, explicitly requests blazing speed because safety has been pre- checked---the macro still has the extra overhead of the now- unnecessary checks. I don't think this is The Right Thing (TM), either.

3. My opinion is that The Right Thing (TM) is to code the macro as follows:

(define-syntax do-range
  (syntax-rules ()
    ((_ (i aa bb) expr ...)
     (let ((a aa)
           (b bb))
       (cond-expand
        ((not unsafe)
         (if (or (not (fixnum? a))
                 (not (fixnum? b)))
             (error 'do-range "non-fixnum limits" a b))))
       (do ((i a (fx+ i 1)))
           ((fx= i b))
         expr ...)))))

This works, but it's pretty yucky. It is the simplest way, given the present behavior of the fxXXX operators, to achieve safety in safe mode (with useful, and immediate, error reporting) and speed in unsafe mode. I submitted the fixnum patch because it would implement the same behavior, but without requiring people using the fxXXX operators to think so much about these issues (and type (cond- expand ...) every time).

Perhaps this situation is familiar to other Chicken users, but I didn't realize that something like #3 was needed to be both safe and fast until yesterday. This is just food for thought---I understand if felix and others want to keep the present behavior of the fxXXX operators.

Will




reply via email to

[Prev in Thread] Current Thread [Next in Thread]