#1307 "if" doesn't give errors for non-booleans

open
nobody
Lisp Core (472)
5
2007-12-29
2007-12-19
Stavros Macrakis
No

The following cases should give errors:

if 3 then x$
if %pi then x$
if "hello" then x$
if [1] then x$
if matrix(...) then x$
if {1,2,3} then x$
(other cases?)

because the constants or containers cannot evaluate to booleans regardless of the lexical environment. Perhaps the same should be true of expressions whose top level is an arithmetic operator, e.g.

if x+1 then ...
if 1/x then ...

but I suppose the arithmetic operators could be overloaded (using pattern matching) to return boolean results in some cases.

I ran into this problem when I mistakenly assumed that Maxima followed the Lisp convention that non-false was true:

if assoc(x,'[["+","-"],["*","//"]]) then ...

when x was "+". Instead of getting an error message, I got an unevaluated conditional

if "-" then ...

which made no sense at all.

Maxima 5.12.0 GCL Windows

Discussion

  • Robert Dodier
    Robert Dodier
    2007-12-29

    Logged In: YES
    user_id=501686
    Originator: NO

    From what I can tell, the parser indeed looks to see if the first argument of "if" is a Boolean expression, but the test is weak -- it only detects non-Boolean expressions for operators which are declared non-Boolean via the POS property. The parser's test appear to pass patently non-Boolean expressions such as numbers.

    e.g.

    prefix ("@@", 100, expr, expr);
    if @@ 1 then a else b;
    => Incorrect syntax: Found algebraic expression where logical expression expected

    Same result with other operators which have POS = $EXPR e.g.: + . ^ ^^

    Maybe changing NUD-CALL in src/nparse.lisp is enough. Here is the current version:

    (defun nud-call (op)
    (let ((tem (and (symbolp op) (getl op '(nud)))) res)
    (setq res
    (if (null tem)
    (if (operatorp op)
    (mread-synerr "~A is not a prefix operator" (mopstrip op))
    (cons '$any op))
    (funcall (cadr tem) op)))
    res))

    Here is a version which causes if 1234 then a else b; to trigger an error:

    (defun nud-call (op)
    (let ((tem (and (symbolp op) (getl op '(nud)))) res)
    (setq res
    (if (null tem)
    (if (operatorp op)
    (mread-synerr "~A is not a prefix operator" (mopstrip op))
    (if ($numberp op) (cons '$expr op) (cons '$any op))) ;; changed this line
    (funcall (cadr tem) op)))
    res))

    Probably ($NUMBERP OP) should be something more complicated. We want to rule out numbers, strings, what else? Maybe objects such as matrices, lists, and sets?

     
  • Robert Dodier
    Robert Dodier
    2007-12-29

    • labels: --> Lisp Core