Re: fixnumXXX and fxXXX names, and other things William D Clinger (19 Jun 2006 14:35 UTC)
Re: fixnumXXX and fxXXX names, and other things John Cowan (19 Jun 2006 15:59 UTC)

Re: fixnumXXX and fxXXX names, and other things William D Clinger 19 Jun 2006 14:35 UTC

Marc Feeley wrote:
> The rationale for the two sets of names is wrong.
> Adding redundant procedures adds confusion.

Your opinion is contrary to mine.  When I use the
fixnum or fx primitives, I first decide whether I
want the quotient ring (with results that may depend
upon the implementation-dependent precision) or the
more errorful primitives (that raise an exception
rather than return a result that might depend upon
the precision).

Having made that decision, I find it less confusing
to use the appropriate prefix consistently than to
mix prefixes.  Indeed, I find it hard to remember
which pairs of primitives behave exactly the same,
as the differences that do exist are often subtle.
If I use the same prefix consistently, however, I
know the operations I use will behave consistently.

> I didn't make this up.  It is the only rationale
> for fixnums in the SRFI 77 rationale:
>
> Fixnum/flonum arithmetic is already supported by
> many systems, mainly for efficiency. Standardization
> of fixnum/flonum arithmetic would increase the portability
> of code that uses it, but we cannot standardize the
> precision of fixnum/flonum arithmetic without making
> it inefficient on some systems, which would defeat its
> purpose.

You overlooked the word "portability", not only in
the paragraph you quoted but in the paragraphs that
precede it.  Note also the word "portable" in those
paragraphs.

Furthermore the first rationale given in the section
on fixnums explains that *the* rationale for the fx
operations is a specific issue of portability.

> By using a multiple values API for some fixnum operations,
> you are limiting the practical portability of those operations.
> This is inconsistent with the rationale.

Your argument, Marc, is that multiple values are slow in
some systems, so portable code shouldn't use them.  That's
like arguing that procedure calls are slow in some systems,
so portable code shouldn't use procedure calls.  The proper
solution is to improve the implementations, and to count on
users being smart enough to avoid slow implementations when
efficiency is a major concern.

> I repeat: in which implementations of Scheme will the
> multiple values API be faster than the equivalent pair
> of operations which return single values?

Implementors are an unpredictable bunch, and efficiency
is not an issue that lends itself to simple answers in
any case.

In Larceny and Petit Larceny, however, I would expect the
fixnum-div+mod, fixnum-div0+mod0, fxdiv+mod, fxdiv0+mod0,
fldiv+mod, fldiv0+mod0, fixnum+/carry, fixnum-/carry, and
fixnum*/carry procedures to be faster than the corresponding
series of calls to single-result procedures.  I would not
expect them to be a great deal faster, however, because
inlining followed by common subexpression elimination would
reduce the duplication these multiple-values-returning
procedures were designed to prevent.  In my opinion, their
performance advantages will be most evident in interpreted
systems that support multiple values efficiently; MzScheme
is one such system.

> I believe that efficient implementations of multiple
> values based on Ashley and Dybvig's method...will not
> gain with the MV API because they need to return the
> multiple values using a function call, and the overhead
> of the function call will drown the few machine cycles
> saved by the combined operation.

You lost me there.  I don't know the instruction-level
details of how multiple values are returned in Chez Scheme,
but I do know you are arguing that two closed calls (to the
separate procedures you favor) and two returns are faster
than one closed call (to the SRFI 77 procedure), a tail
call to values (which will probably be inlined, and consist
of just a few machine instructions), and the return from
the values procedure.  Your argument doesn't add up.

> The choice of a MV API for these operations is poor engineering.

Your conclusion is unsupported.  I agree with your earlier
argument that many systems are using poorly engineered
implementations of multiple values, but the responsibility
for fixing that problem lies with implementors, not with
Scheme programmers in general.

> Can you quantify what you mean by "reasonably efficient"
> for the fixnum operations?

To some extent, but it should be obvious that the efficiency
will vary greatly from one implementation to another, and
also from operation to operation.

> Do you mean as fast as the equivalent operation in C?

Since C is an unsafe language, it would seem that the proper
comparison would be with implementations of Scheme that will
implement the unsafe mode mentioned in SRFI 77.  In unsafe
mode, on most architectures, the fixnum and fx comparisons
and basic arithmetic operations should compile into a single
machine instruction, the same as in C.

Even in safe code, and even for generic operations such as +,
some compilers can, in some circumstances, compile the call
to + into a single machine instruction.  My Twobit compiler
does that sometimes, even today.  With the proposed R6RS
library system, that will happen more often.  (That, by the
way, is my response to one of Per Bothner's points.)

As for the worst case, in safe code, with generic arithmetic,
inlining the usual procedures (which I expect to be justified
by the R6RS library system), a call to + with two arguments
that turn out to be fixnums, whose sum is a fixnum, currently
takes somewhere between three (Sparc) and seven (IA32) dynamic
instructions.

> I fear that unless the fixnum operations are inlined, the
> procedure call to the definition in the reference implementation
> will slow down the operation by a factor of 10 or more, rendering
> it useless in practice for writing efficient code.

I assume that, in compiled implementations that aspire to
efficiency, the fixnum comparisons and basic arithmetic
operations (e.g. fixnum+) will be inlined.  Most of those
implementations already inline the fixnum case for generic
arithmetic, and most already inline their own idiosyncratic
extensions for fixnum-specific arithmetic.

The potential standardization represented by SRFI 77 won't
make efficient implementations less efficient, and it won't
make inefficient implementations more efficient.  What it
will accomplish is to make Scheme programs more portable.

Programmers won't have to worry about implementations that
convert to inexact numbers because they don't support
exact rational arithmetic of unlimited precision, and they
will be able to write fixnum-specific, flonum-specific,
exact-specific, and inexact-specific arithmetic without
having to change the procedure names when porting to a
different implementation.

Will