1

So I have classes

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

(defclass bar (foo)
  ((c :initarg :c)))

And a constructor

(defun make-foo (a b)
  (make-instance 'foo :a a :b b))

Is there a simple way to define a function that takes in an existing FOO and produces a BAR with the extra slot C defined? I.e. without having to list out all the slots as such:

(defun make-bar-from-foo (existing-foo c)
  (make-instance 'bar :a (a existing-foo) :b (b existing-foo) :c c))
wrongusername
  • 18,564
  • 40
  • 130
  • 214
  • 5
    There's nothing built-in. Are you sure you don't want to just use `CHANGE-CLASS` to change `existing-foo` into a `bar`? – Barmar May 24 '15 at 08:11
  • @Barmar oh didn't know about `CHANGE-CLASS`, thanks! – wrongusername May 24 '15 at 08:21
  • 1
    CLOS doesn't have constructors, per se. If what you want is a new `bar` object, `change-class` is probably not what you want, as it actually changes the object. – Vatine May 24 '15 at 15:58
  • @Barmar you guys want to submit that as an answer? thank you – wrongusername May 25 '15 at 00:22
  • @Vatine you guys want to submit that as an answer? thank you – wrongusername May 25 '15 at 00:22
  • 1
    Well, it comes down to what you really need to accomplish. As @Vatine says, if you use `CHANGE-CLASS` you don't get a new object, it modifies the original object in place. You could make a copy of `foo` and then change its class, but CLOS doesn't have a built-in copy operation, so you'd have to code that (it would be similar to `make-bar-from-foo` except that it wouldn't add the `c` slot. – Barmar May 25 '15 at 01:30
  • In addition to what @Barmar said, you can adapt this method of copying objects to your needs by changing the way the copy target is created. http://stackoverflow.com/questions/11067899/is-there-a-generic-method-for-cloning-clos-objects You can also use closer-mop for accessing metaobject functionality in a more portable way. – sid_cypher Jun 03 '15 at 14:45

1 Answers1

0

This might be an option:

(defclass foo ()
  ((a :initarg :a :accessor a)
   (b :initarg :b :accessor b)
   (initargs :accessor initargs))) ;Remember the initargs here.

(defclass bar (foo)
  ((c :initarg :c :accessor c)))

(defmethod initialize-instance :after ((foo foo) &rest initargs)
  (setf (initargs foo) initargs))

(defun make-bar-from-foo (foo c)
  (apply #'make-instance 'bar :c c (initargs foo))) ;And use them here.
Lars Brinkhoff
  • 13,542
  • 2
  • 28
  • 48