Using initargs with define-interface
Hi everyone,
I'm wondering whether the following behavior is expected, well known,
&c. I define a class for which make-instance accepts an :items
initarg. The class definition is such that if the initarg isn't
supplied, there's a default value. (The phenomenon I'm describing
works with either with a :default-initarg or an :initform—the code
below uses the former, but I discovered this behavior using the
latter.)
If I define an interface one of whose panes is an instance of the
defined class, I can specify :items (:initarg :items) to get
make-instance to accept an :items initarg and pass it along to the
class instance. However, the behavior when :items is not given is
rather unlike what I'd expect for omitted initargs. The default value
for items (from the class definition) is clobbered.
(defclass one-to-ten-list (capi:list-panel) ()
(:default-initargs
:items (list 1 2 3 4 5 6 7 8 9 10)))
;; The list-panel has 1, …, 10
(capi:contain (make-instance 'one-to-ten-list))
(capi:define-interface one-to-ten-list-interface () ()
(:panes
(lp one-to-ten-list
:items (:initarg :items)))
(:default-initargs
:width 200
:height 200))
;; the list panel in here has 1, …, 5
(capi:display
(make-instance 'one-to-ten-list-interface
:items (list 1 2 3 4 5)))
;; the list panel here has nothing.
(capi:display (make-instance 'one-to-ten-list-interface))
The expansion of the define-interface macro makes it clear what's
happening. There's no provision made for what happens if :item is not
supplied when making an instance of the interface. It means that the
"initarg" is really just behaving like any other keyword argument, and
less like an initarg from a class definition.
(DEFMETHOD CAPI::INITIALIZE-INTERFACE
:AFTER
((#:SELF158022 ONE-TO-TEN-LIST-INTERFACE)
&REST
#:ARGS158023
&KEY
((:ITEMS #:ITEMS158024))
&ALLOW-OTHER-KEYS)
(WITH-SLOTS (LP) #:SELF158022
(DECLARE (IGNORABLE LP))
(LET ((CAPI::SELF #:SELF158022) (CAPI:INTERFACE #:SELF158022))
(DECLARE (IGNORABLE CAPI::SELF CAPI:INTERFACE))
(SETF (SLOT-VALUE #:SELF158022 'LP)
(MAKE-INSTANCE 'ONE-TO-TEN-LIST :ITEMS #:ITEMS158024 :NAME 'LP))
(SETF (SLOT-VALUE #:SELF158022 'CAPI::PANES)
(LIST* (SLOT-VALUE #:SELF158022 'LP)
(SLOT-VALUE #:SELF158022 'CAPI::PANES))))))
Of course, as author of both the class and the interface, I can
specify the default value in the interface definition in addition to
the class definition, but having to do this seems a bit ugly to me
(though I'm going to do it until I hear back), and makes the "initarg"
much less like an initarg. I.e., I can do this:
(defclass one-to-ten-list (capi:list-panel) ()
(:default-initargs
:items (list 1 2 3 4 5 6 7 8 9 10)))
(capi:define-interface one-to-ten-list-interface () ()
(:panes
(lp one-to-ten-list
:items (:initarg (items (list 1 2 3 4 5 6 7 8 9 10)))))
(:default-initargs :width 200 :height 200))
Is this the behavior you would have expected? Have you run into this
problem and done the same thing? Found a different workaround?
Thanks in advance, //JT
--
Joshua Taylor, http://www.cs.rpi.edu/~tayloj/