Lisp HUG Maillist Archive

Keyword argument ordering

I haven't found this in the spec, so I'm hoping I'm just blind and this isn't implementation dependent. I'm implementing a kind of "copy-with-overrides" function, I'll get to that in a second.

(defclass foo ()
  ((a :initarg :a :accessor foo-a)))


(foo-a (make-instance 'foo :a 10 :a 20 :a 30))  ;=> 10

As you can see, the first keyword to match the initarg is used. The same holds true if I use a defstruct to define foo instead of a class. Will this always be the case across implementations?

Next, because perhaps someone has a better solution, my copy-with-overrides function generally works something like this:

(defun clone-foo (foo &key a)
  (make-instance 'foo :a (or a (foo-a foo))))

Except that it has a lot more keys to override. I have another instance where the initargs are built up and I'm going to use #'apply to make the instance using a spec that was built from somewhere else, but I'd like to override aspects of it. If the above keyword ordering holds true then I should be able to do this:

(defun clone-foo (foo spec &rest initargs &key a)
  (apply #'make-instance 'foo (nconc initargs spec)))

Are these valid assumptions?

Anyone have other suggestions for how to go about doing this in a better way?

Thanks!

Jeff M.

Re: Keyword argument ordering

On Wed, Sep 18, 2013 at 10:47 AM, Jeffrey Massung <massung@gmail.com> wrote:
> I haven't found this in the spec, so I'm hoping I'm just blind and this
> isn't implementation dependent. I'm implementing a kind of
> "copy-with-overrides" function, I'll get to that in a second.
>
> (defclass foo ()
>   ((a :initarg :a :accessor foo-a)))
>
> (foo-a (make-instance 'foo :a 10 :a 20 :a 30))  ;=> 10
>
> As you can see, the first keyword to match the initarg is used. The same
> holds true if I use a defstruct to define foo instead of a class. Will this
> always be the case across implementations?

The leftmost gets used [1]:

3.4.1.4 Specifiers for keyword parameters
The keyword parameter specifiers are, like all parameter specifiers,
effectively processed from left to right. For each keyword parameter
specifier, if there is an argument pair whose name matches that
specifier's name (that is, the names are eq), then the parameter
variable for that specifier is bound to the second item (the value) of
that argument pair. If more than one such argument pair matches, the
leftmost argument pair is used.

[1] http://www.lispworks.com/documentation/lw50/CLHS/Body/03_dad.htm

> Next, because perhaps someone has a better solution, my copy-with-overrides
> function generally works something like this:
>
> (defun clone-foo (foo &key a)
>   (make-instance 'foo :a (or a (foo-a foo))))
>
> Except that it has a lot more keys to override. I have another instance
> where the initargs are built up and I'm going to use #'apply to make the
> instance using a spec that was built from somewhere else, but I'd like to
> override aspects of it. If the above keyword ordering holds true then I
> should be able to do this:
>
> (defun clone-foo (foo spec &rest initargs &key a)
>   (apply #'make-instance 'foo (nconc initargs spec)))
>
> Are these valid assumptions?

This should work, and I don't think it's all that uncommon to do.

//JT
-- 
Joshua Taylor, http://www.cs.rpi.edu/~tayloj/

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Updated at: 2020-12-10 08:35 UTC