How to pass superclass object to subclass constructor?

Let's say I have a class Awith several slots:

(defclass a ()
  ((a-1 :initarg :a-1)
   (a-2 :initarg :a-2)))

And a class Bthat inherits from A:

(defclass b (a)
  ((b-1 :initarg :b-1)))

If I want to create an instance B, it will make-instanceoffer me slots :a-1, :a-2and :b-1.

Here's a crazy idea: what if I want to create an instance Busing an existing instance Aand fill only the slot b-1?

PS. Why this may be useful: if it Aimplements some common methods that it Binherits directly without adding anything new. In an alternative approach, when an instance Ashould be a slot in B, I would need to write trivial wrappers of methods to call these methods in this slot.

The only way I can think of: in an auxiliary constructor, decompose the object Aand pass the corresponding slots to make-instancefor B, that is:

(defun make-b (b-1 a-obj)
  (with-slots (a-1 a-2) a-obj
    (make-instance 'b :b-1 b-1 :a-1 a-1 :a-2 a-2)))

Are there any better ways to do this? (or perhaps this approach leads to a very poor design, and should I avoid it at all?)

+4
source share
2 answers

, . : , , A , :initarg, , , initialize-instance shared-initialize?

, ,

  • , A, -

    (defgeneric initargs-for-copy (object)
      (:method-combination append)
      (:method append (object) nil))
    
    (defmethod initargs-for-copy append ((object a))
      (list :a-1 (slot-value object 'a-1) :a-2 (slot-value object 'a-2)))
    
    (defun make-b (b-1 a-obj)
      (apply #'make-instance 'b :b-1 b-1 (initargs-for-copy a-obj)))
    
  • MOP ( Lisp , closer-mop, quicklisp)

    (defun list-init-args (object)
      (let* ((class (class-of object))
             (slots (closer-mop:class-slots class)))
        (loop
          for slot in slots
          for name = (closer-mop:slot-definition-name slot)
          for keyword = (closer-mop:slot-definition-initargs slot)
          when (and keyword (slot-boundp object name))
            nconc (list (car keyword) (slot-value object name)))))
    
    (defun make-b (b-1 a-obj)
       (apply #'make-instance 'b :b-1 b-1 (list-init-args a-obj)))
    
  • change-class, A B .

: , . ( ) . , B A: B A (.. is-a?)? ?

+4

, , , "" .

(defclass prototype-mixin ()
  ((parent :initarg :parent :initform nil :accessor parent)))

(defmethod slot-unbound (c (p prototype-mixin) slot)
  (declare (ignore c))
  (let ((parent (parent p)))
    (if parent
      (slot-value parent slot)
      (call-next-method))))

:

(defclass a ()
  ((slot :initarg :slot)))

(defclass b (a prototype-mixin) 
  ((other :initarg :other)))

b a, parent b a. b a, b slot. , , "" , a. , b.

comp.lang.lisp.

+3

Source: https://habr.com/ru/post/1627130/


All Articles