On Sun, May 21, 2017 at 05:14:02PM +0200, lemonboy wrote:
> Hi Peter,
> I expect the `fxX?` procedures as 1:1 replacements of the standard
> `fxN` ones with the
> only exception being the way the overflow is handled.
> The point where the two diverge is the handling of the input
> parameters: while the latter
> follow the garbage-in garbage-out philosophy the former takes a
> "stricter" approach and
> rejects the non-fixnum arguments by returning `#f`.
> I think that's the by-product of a lax check on the input parameters
> rather than a design
> decision and even though this check works just fine in practice there
> are some drawbacks:
> - We can't give to their arguments the type `(or fixnum false)`, this
> means we can't possibly
>  warn the user if they pass the wrong argument (the standard
> procedures allow this);

I don't really care that much about this, so unless others have similar
concerns I think we can apply this change.

However, they shouldn't be #:enforce; they don't raise an error when
their types are fixnum or false, which is what enforce means: if the
code goes beyond this expression, you may assume the input types are
correct.

I believe these procedures can be marked #:pure, though, since they
don't have *any* side effects (except for fx/?, since it will raise an
exception when dividing by zero).

Speaking of which: can't all the other fixnum-specific procedures be
pure as well?  Except for fx/, of course.

> - There's no way to distinguish the result of `(fx+? 'foo 3)` from the
> result of an
>  overflowing calculation, couple it with the lack of any warning and
> you're in for a nice bug
>  hunt.

Speaking of strange bugs, I'm wondering whether these fixnum procedures
should be foldable at all (that also goes for the procedures that are
already in types.db).  Consider the case where you're compiling on a
64-bit machine.  The compiler folds the fixnum operations at
compile-time, resulting in a fixnum.  However, if the fixnum is not
representable as a fixnum on the target computer, it will be represented
as a bignum (or on CHICKEN 4, as a flonum).

This not only produces a different answer than when the same code would
be compiled on the 32-bit machine and in the interpreter, but it also
may trigger other unexpected behaviour resulting from a mismatch of the
expectation that you're dealing with fixnums only.  For example, a
specialised unsafe version of a generic procedure might end up being
specialised for fixnums, but on a 32-bit platform it might still receive
a bignum (or a flonum on master).

Hm, I wonder if this stuff causes other problems as well...

Anyway, attached is a signed-off version of your patch without
the #:enforce and with the #:pure annotations, and a second patch
which removes #:foldable from the other fixnum operations too.

Cheers,
Peter
From 2af71bd754ee57249e3f445e9d199de152f5147e Mon Sep 17 00:00:00 2001
From: LemonBoy <thatle...@gmail.com>
Date: Fri, 19 May 2017 22:45:28 +0200
Subject: [PATCH 1/2] Add entries in the types.db for the fxX? ops

Signed-off-by: Peter Bex <pe...@more-magic.net>
---
 types.db | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/types.db b/types.db
index 7e30466..ad8a462 100644
--- a/types.db
+++ b/types.db
@@ -1191,6 +1191,15 @@
 (chicken.fixnum#fxxor (#(procedure #:clean #:foldable) chicken.fixnum#fxxor (fixnum fixnum) fixnum))
 (chicken.fixnum#fxlen (#(procedure #:clean #:foldable) chicken.fixnum#fxlen (fixnum) fixnum))
 
+(chicken.fixnum#fx+? (#(procedure #:pure)
+    chicken.fixnum#fx+? ((or fixnum false) (or fixnum false)) (or fixnum false)))
+(chicken.fixnum#fx-? (#(procedure #:pure)
+    chicken.fixnum#fx-? ((or fixnum false) (or fixnum false)) (or fixnum false)))
+(chicken.fixnum#fx*? (#(procedure #:pure)
+    chicken.fixnum#fx*? ((or fixnum false) (or fixnum false)) (or fixnum false)))
+(chicken.fixnum#fx/? (#(procedure #:clean)
+    chicken.fixnum#fx/? ((or fixnum false) (or fixnum false)) (or fixnum false)))
+
 (gensym (#(procedure #:clean) gensym (#!optional (or string symbol)) symbol))
 
 (get (#(procedure #:clean #:enforce) get (symbol symbol #!optional *) *)
-- 
2.1.4

From b554163c44d4168128707784fafa40f8096ccef4 Mon Sep 17 00:00:00 2001
From: Peter Bex <pe...@more-magic.net>
Date: Sun, 21 May 2017 18:23:12 +0200
Subject: [PATCH 2/2] Remove #:foldable for fixnum-specific ops

What's a fixnum on a 64-bit platform may not be a fixnum on a 32-bit
platform, which might cause problems with unsafe specialisation.
---
 types.db | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/types.db b/types.db
index ad8a462..cc7f9a2 100644
--- a/types.db
+++ b/types.db
@@ -1165,31 +1165,31 @@
 (chicken.fixnum#fixnum-bits fixnum)
 (chicken.fixnum#fixnum-precision fixnum)
 
-;;XXX should these be enforcing?
-(chicken.fixnum#fx- (#(procedure #:clean #:foldable) chicken.fixnum#fx- (fixnum fixnum) fixnum))
-(chicken.fixnum#fx* (#(procedure #:clean #:foldable) chicken.fixnum#fx* (fixnum fixnum) fixnum))
-(chicken.fixnum#fx/ (#(procedure #:clean #:foldable) chicken.fixnum#fx/ (fixnum fixnum) fixnum))
-(chicken.fixnum#fxgcd (#(procedure #:clean #:foldable) chicken.fixnum#fxgcd (fixnum fixnum) fixnum))
-(chicken.fixnum#fx+ (#(procedure #:clean #:foldable) chicken.fixnum#fx+ (fixnum fixnum) fixnum))
-(chicken.fixnum#fx< (#(procedure #:clean #:foldable) chicken.fixnum#fx< (fixnum fixnum) boolean))
-(chicken.fixnum#fx<= (#(procedure #:clean #:foldable) chicken.fixnum#fx<= (fixnum fixnum) boolean))
-(chicken.fixnum#fx= (#(procedure #:clean #:foldable) chicken.fixnum#fx= (fixnum fixnum) boolean))
-(chicken.fixnum#fx> (#(procedure #:clean #:foldable) chicken.fixnum#fx> (fixnum fixnum) boolean))
-(chicken.fixnum#fx>= (#(procedure #:clean #:foldable) chicken.fixnum#fx>= (fixnum fixnum) boolean))
-(chicken.fixnum#fxand (#(procedure #:clean #:foldable) chicken.fixnum#fxand (fixnum fixnum) fixnum))
-(chicken.fixnum#fxeven? (#(procedure #:clean #:foldable) chicken.fixnum#fxeven? (fixnum) boolean))
-(chicken.fixnum#fxior (#(procedure #:clean #:foldable) chicken.fixnum#fxior (fixnum fixnum) fixnum))
-(chicken.fixnum#fxmax (#(procedure #:clean #:foldable) chicken.fixnum#fxmax (fixnum fixnum) fixnum))
-(chicken.fixnum#fxmin (#(procedure #:clean #:foldable) chicken.fixnum#fxmin (fixnum fixnum) fixnum))
-(chicken.fixnum#fxmod (#(procedure #:clean #:foldable) chicken.fixnum#fxmod (fixnum fixnum) fixnum))
-(chicken.fixnum#fxrem (#(procedure #:clean #:foldable) chicken.fixnum#fxrem (fixnum fixnum) fixnum))
-(chicken.fixnum#fxneg (#(procedure #:clean #:foldable) chicken.fixnum#fxneg (fixnum) fixnum))
-(chicken.fixnum#fxnot (#(procedure #:clean #:foldable) chicken.fixnum#fxnot (fixnum) fixnum))
-(chicken.fixnum#fxodd? (#(procedure #:clean #:foldable) chicken.fixnum#fxodd? (fixnum) boolean))
-(chicken.fixnum#fxshl (#(procedure #:clean #:foldable) chicken.fixnum#fxshl (fixnum fixnum) fixnum))
-(chicken.fixnum#fxshr (#(procedure #:clean #:foldable) chicken.fixnum#fxshr (fixnum fixnum) fixnum))
-(chicken.fixnum#fxxor (#(procedure #:clean #:foldable) chicken.fixnum#fxxor (fixnum fixnum) fixnum))
-(chicken.fixnum#fxlen (#(procedure #:clean #:foldable) chicken.fixnum#fxlen (fixnum) fixnum))
+;;XXX These aren't enforcing, and aren't foldable due to 32/64-bit issues
+(chicken.fixnum#fx- (#(procedure #:clean) chicken.fixnum#fx- (fixnum fixnum) fixnum))
+(chicken.fixnum#fx* (#(procedure #:clean) chicken.fixnum#fx* (fixnum fixnum) fixnum))
+(chicken.fixnum#fx/ (#(procedure #:clean) chicken.fixnum#fx/ (fixnum fixnum) fixnum))
+(chicken.fixnum#fxgcd (#(procedure #:clean) chicken.fixnum#fxgcd (fixnum fixnum) fixnum))
+(chicken.fixnum#fx+ (#(procedure #:clean) chicken.fixnum#fx+ (fixnum fixnum) fixnum))
+(chicken.fixnum#fx< (#(procedure #:clean) chicken.fixnum#fx< (fixnum fixnum) boolean))
+(chicken.fixnum#fx<= (#(procedure #:clean) chicken.fixnum#fx<= (fixnum fixnum) boolean))
+(chicken.fixnum#fx= (#(procedure #:clean) chicken.fixnum#fx= (fixnum fixnum) boolean))
+(chicken.fixnum#fx> (#(procedure #:clean) chicken.fixnum#fx> (fixnum fixnum) boolean))
+(chicken.fixnum#fx>= (#(procedure #:clean) chicken.fixnum#fx>= (fixnum fixnum) boolean))
+(chicken.fixnum#fxand (#(procedure #:clean) chicken.fixnum#fxand (fixnum fixnum) fixnum))
+(chicken.fixnum#fxeven? (#(procedure #:clean) chicken.fixnum#fxeven? (fixnum) boolean))
+(chicken.fixnum#fxior (#(procedure #:clean) chicken.fixnum#fxior (fixnum fixnum) fixnum))
+(chicken.fixnum#fxmax (#(procedure #:clean) chicken.fixnum#fxmax (fixnum fixnum) fixnum))
+(chicken.fixnum#fxmin (#(procedure #:clean) chicken.fixnum#fxmin (fixnum fixnum) fixnum))
+(chicken.fixnum#fxmod (#(procedure #:clean) chicken.fixnum#fxmod (fixnum fixnum) fixnum))
+(chicken.fixnum#fxrem (#(procedure #:clean) chicken.fixnum#fxrem (fixnum fixnum) fixnum))
+(chicken.fixnum#fxneg (#(procedure #:clean) chicken.fixnum#fxneg (fixnum) fixnum))
+(chicken.fixnum#fxnot (#(procedure #:clean) chicken.fixnum#fxnot (fixnum) fixnum))
+(chicken.fixnum#fxodd? (#(procedure #:clean) chicken.fixnum#fxodd? (fixnum) boolean))
+(chicken.fixnum#fxshl (#(procedure #:clean) chicken.fixnum#fxshl (fixnum fixnum) fixnum))
+(chicken.fixnum#fxshr (#(procedure #:clean) chicken.fixnum#fxshr (fixnum fixnum) fixnum))
+(chicken.fixnum#fxxor (#(procedure #:clean) chicken.fixnum#fxxor (fixnum fixnum) fixnum))
+(chicken.fixnum#fxlen (#(procedure #:clean) chicken.fixnum#fxlen (fixnum) fixnum))
 
 (chicken.fixnum#fx+? (#(procedure #:pure)
     chicken.fixnum#fx+? ((or fixnum false) (or fixnum false)) (or fixnum false)))
-- 
2.1.4

Attachment: signature.asc
Description: Digital signature

_______________________________________________
Chicken-hackers mailing list
Chicken-hackers@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-hackers

Reply via email to