[Top][All Lists]
[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