The context for my post was this:
(define-presentation-to-command-translator xlate-set-lcursor (clim:blank-area com-set-cursor plotter :documentation "Set Left Cursor" :gesture :select :tester ((object window) (declare (ignore object)) (typep window 'basic-chart-pane))) (object x y window) (%set-a-cursor (chart-pane-chart window) 'lcursor x y window))
where originally I omitted 'object' from the next to last line resulting in the wrong values being presented to the %set-a-cursor function. User error on my part but LispWorks CLIM2 did what I expected anyway thus keeping me ignorant of my omission. Perhaps LW was able to infer what I wanted.
On 1/10/2021 2:45 AM, Lauren P wrote:
Hey,
On Sat, Jan 9, 2021, 11:21 Paul Werkowski <pw@snoopy.qozzy.com mailto:pw@snoopy.qozzy.com> wrote:
(defun make-translator-fun (args body) (cond ((null args) (warn "OBJECT parameter is obligatory (adding ignored parameter)") (let ((object-arg (gensym "OBJECT-ARG"))) `(lambda (,object-arg &key &allow-other-keys) (declare (ignore ,object-arg)) ,@body))) (t `(lambda (,(car args) &key ,@(cdr args) &allow-other-keys) (declare (ignorable ,(car args))) ,@body)))) I guess the above does the right thing if ARGS is NIL but won't catch the case of ARGS incorrectly given as, for instance, (x y window) instead of (object x y window).
I would give it an explicit parameter so it takes (OBJECT-ARG ARGS BODY) so autodoc shows where the object argument goes without having to remember to read the docstring.
I'd put in a destructuring bind at the T case and then test that... it should bomb in the compiler if you pass it (NIL X Y WINDOW) as-is: you'll need to gensym and DECLARE IGNORE if it's a NIL.
If you wrap it in a macro the way I write that lambda list is ((OBJECT-ARG &REST ARGS) &BODY BODY); it is displayed by autodoc and the destructuring bind catches it at compile time. If you really want to accept a no arguments form, I tend to use NAME* for the alternative form and make it a wrapper stub, otherwise I prefer to assume "forgot arguments" and error.
I wouldn't set the object argument ignorable in the T case unless it was typed in as NIL, as it can hide bugs in the body code. Better to let the user specify ignorable in the BODY if they are sure they don't need it.
(More of a style thing, I find it cleaner to normalize the argument list to replace the empty list with (NIL) so it works with destructuring bind: you can get rid of the main branch and only type the bulk of the code once, since you need to check for a gensym and ignore declaration in the T case as well. Also, leave out &ALLOW-OTHER-KEYS unless absolutely necessary... I've found it makes it exceedingly difficult to catch typos.)
Hope this is useful for you!