Menu ▾ ▴

#3970 draw does not do adequate argument checking

None
closed
draw (19)
5
2022-06-03
2022-04-28
Leo Butler
No

The following syntax error should be caught by draw:

(%i2) draw2d(explicit(sin));

Maxima encountered a Lisp error:

 Condition in MACSYMA-TOP-LEVEL [or a callee]: INTERNAL-SIMPLE-PROGRAM-ERROR: MACSYMA-TOP-LEVEL [or a callee] requires more than one argument.

Automatically continuing.
To enable the Lisp debugger set *debugger-hook* to nil.

Discussion

  • Raymond Toy

    Raymond Toy - 2022-04-28

    At first glance, it seems as if we need to modify explicit to take rest args so that we can check the number of args and produce a nice error function. defmfun would do this for us, but that would expose a $explicit function that we probably don't want to have.

    Perhaps a new defmfun-internal macro would be useful for cases like this. Basically like defmfun, but doesn't create $foo function.

     
    • Leo Butler

      Leo Butler - 2022-04-29

      I think that is one approach. A related one is to have a beefed-up defun that allows a syntax like

      (defun+ explicit 
      ((fun type-of-fun fun-error-message) 
      (var type-of-var var-error-message) 
      (xmin type-of-xmin xmin-error-message) 
      (xmax type-of-xmax xmax-error-message))
      body)
      

      This could expand into a defun with all args made optional and a collection of assertions to do the argument type checking and emit an error when needed. That might have uses beyond draw. This would also incorporate Gunter's suggestion.

      Another option is write an argument parser for draw and catch the syntax errors there.

       
      • Raymond Toy

        Raymond Toy - 2022-05-22

        Thanks for explaining what type-of-fun and fun-error-message would do.

        While such things are possible and also part of defstructs and defclasses, it seems unnatural for lisp functions (and macros) to do the same. (Yes, loop allows this.) It seems typically lisp style would be to declare these, and/or use check-type explicitly to detect types.

        But I understand it makes it easier to see (sort of) that the arguments are expected to have certain types. But this could also be seen from the declare statements.

         
        • Raymond Toy

          Raymond Toy - 2022-05-28

          I think this has limited utility, at least in the context of draw. For example, the type of xmin has to be basically T because xmin can be any kind of maxima expression that evaluates to a numerical value. So I'm not sure what type-of-xmin would really say.

          On the other hand, if this is really desired, I think it can be layered on top of the new defun-checked by extracting the variable names and calling defun-checked appropriately, and updating the body to add the appropriate declarations or check-type to check the argument type and produce the given error message.

           
          • Stavros Macrakis

            I don't follow. Why would you check the unevaluated expression for xmin? Its value must be numerical, no?

             
  • Gunter Königsmann

    Would it make sense and not too much overhead if defmfun-internal accepted an optional argument with a more specific text about what explicit() and similar do?

     
    • Raymond Toy

      Raymond Toy - 2022-05-22

      What does this optional argument with text do? How is it supposed to be used? It sounds somewhat like a docstring for explicit, but I'm not sure. defmfun and friends already support a docstring.

       
  • Raymond Toy

    Raymond Toy - 2022-05-05

    Can you, Leo, explain a bit more on what "type-of-fun" does and what "fun-error-message" is supposed to do?

    I think I can guess, but, I want to know what you had in mind.

    I personally would rather have the error message in the code since it's more general that way because in general you might want to give more information about what's illegal. I really error messages that say "illegal", when there's enough information to say "illegal because smin (xmin-val) must be <= xmax (xmax-val)".

     
    • Leo Butler

      Leo Butler - 2022-05-17

      Ray, I have in mind that type-of-fun could be a type checker for the argument fun. It would return t or nil. And fun-error-message could be a string or a thunk that emits an informative error in the event that type-of-fun evaluates to nil. I think both could be optional, so that if type-of-fun is omitted, the default evaluates to t and if fun-error-message is omitted, some default error message is emitted.

      I think this could be scaffolded on top of defun-checked.

       
  • Raymond Toy

    Raymond Toy - 2022-05-06

    I hacked something together, kind of resurrecting the old defun-checked (but in a different way). Now I get

    draw2d(explicit(sin));
    
    explicit(fcn, var, minval, maxval): expected exactly 4 arguments but got 1: 
                                                                              [sin]
     -- an error. To debug this try: debugmode(true);
    

    I just changed (defun explicit ...) to (defun-checked explicit ...).

    defmfun now uses defun-checked to do the heavy lifting.

    You can find the changes on the rtoy-3970-defmfun-internal branch.

     

    Last edit: Raymond Toy 2022-05-06
    • Kris Katterjohn

      Kris Katterjohn - 2022-05-12

      Ray: I didn't test out your branch, but I glanced at some commits. It looks like you undid the change which removes the leading $ from names when creating the impl names, so it looks like $FOO again has an impl name $FOO-IMPL.

      Removing the leading $ was introduced because the impl names were visible in apropos results. See bug [#3643].

       

      Related

      Bugs: #3643

      • Raymond Toy

        Raymond Toy - 2022-05-22

        Good point. I'll make sure to fix that soon.

         
  • Raymond Toy

    Raymond Toy - 2022-06-03

    This is fixed in commit [9f073b].

    (%i2) draw2d(explicit(sin));
    explicit(fcn, var, minval, maxval): expected exactly 4 arguments but got 1: 
                                                                              [sin]
     -- an error. To debug this try: debugmode(true);
     (%i3) draw2d(explicit(sin,x));
    
    explicit(fcn, var, minval, maxval): expected exactly 4 arguments but got 2: 
                                                                           [sin, x]
     -- an error. To debug this try: debugmode(true);
    

    I think I got all of the functions used by draw updated to catch incorrect number of args and produce a nice maxima error and message, in line with how other maxima functions work.

    I did not, however, incorporate Leo's suggestion about enhancing defun/defmfun to include type info and error strings. I think if that's really desired, we can implement that on top of defun-checked and/or defmfun.

     

    Related

    Commit: [9f073b]

  • Raymond Toy

    Raymond Toy - 2022-06-03
    • labels: --> draw
    • status: open --> closed
    • assigned_to: Raymond Toy
     

Log in to post a comment.