Changes for bug 2085440



Steve Haflich wrote:
> Raymond Toy <raymond.toy at stericsson.com> wrote:
>
>    However, there will be a slight cost in speed and consing for functions
>    that have a fixed number of arguments.  So that maxima can do the
>    checking, the compiled function now takes a &rest arg which we can check
>    for the number of arguments.  Previously, the compiled function had
>    exactly the desired number of arguments.
>    
>    I think for consistency, it's nice that the compiled function works the
>    same as the interpreted.  But we do pay a little in speed and consing. 
>
> I think this is unfortunate.  The ANS for CL defines argument checking
> for "safe" code, and every implementation that purports to confurm to
> the ANS should support it.  The implementation can perform argument
> checking more efficiently than application code.
>   
Ok.  I think I was not clear enough.  Here is the bug report:

(%i1) f(x) := x$
(%i2) f(1,2);
Too many arguments supplied to f(x): [1,2]

That's reasonable.  Here's what happens when you compile it (using gcl,
based on the error message)


(%i3) compile(f)$

(%i4) f(1,2);
 Maxima encountered a Lisp error:
Error in MACSYMA-TOP-LEVEL [or a callee]: MACSYMA-TOP-LEVEL [or a callee]
requires less than two arguments.

And you're thrown back to maxima top-level by default.

So checking is being done by the Lisp implementation.  No problem with that.

Here's what I get with the change:

(%o146)                               [f]
(%i147) f(1,2);

Too many arguments supplied to f(x):
[1, 2]
 
One issue with the current implementation is that if you're doing some
long calculation, you'll get an error, but no indication of what
function call caused it.  The interpreted version at least mentions the
functions and the arguments.  The new version does the same.

The main difference is that the new function is compiled to

#'(LAMBDA
        (&REST NARG-REST-ARGUMENT
         &AUX (|mlexpr NARGS| (LENGTH NARG-REST-ARGUMENT)))
      (BLOCK $F
        (COND
          ((/= |mlexpr NARGS| 1)
           (MERROR "Too ~M arguments supplied to ~M:~%~M"
                   (IF (< |mlexpr NARGS| 1) "few" "many")
                   (CONS (CONS '$F NIL) '($X))
                   (LIST* '(MLIST) NARG-REST-ARGUMENT)))
          (T
           ((LAMBDA ($X) (DECLARE (SPECIAL $X)) $X) (ARG 1)))))))

It used to be compiled to

#(#'(LAMBDA ($X) (DECLARE (SPECIAL $X)) (BLOCK $F $X)))

Note also, that for maxima functions like h(x,[r]), maxima compiles the
function to something like the above.  We could just as easily not do
anything  special and have the underlying Lisp do all the argument checking.

Maybe the expectation is that for compiled functions, you get to debug
the result using the Lisp's debugger.  (Somewhat difficult since the
default is to turn off the Lisp debugger, and just through to maxima's
top-level by default.)

If that's the case, we should compile h(x,[r]) to use Lisp argument
checking.

Ray