(defobject MyListElement ()
  (property next nil
            data nil))
            
(defobject MyList ()
  (property head nil
            tail nil))

(defmethod (MyList 'AddToList data)
  (let ((newElement (clone MyListElement 'data data))
        (tail (getp self 'tail)))
    (if tail
      (setp! tail 'next newElement)
      (setp! self 'head newElement))
    (setp! self 'tail newElement)))

(defmethod (MyList 'Print)
  (let ((element (getp self 'head)))
    (while element
      ((getp element 'data) 'Print)
      (set! element (getp element 'next)))))

(defobject MyNumber ()
  (property value 0))

(defmethod (MyNumber 'Print)
  (print "Number: " (getp self 'value) "\n"))

(defobject MyPoint ()
  (property x 0
            y 0))

(defmethod (MyPoint 'Print)
  (print "Point: " (getp self 'x) "," (getp self 'y) "\n"))

(define (main)
  (let ((list1 (clone MyList))
        (list2 (clone MyList))
        (n1 (clone MyNumber 'value 10))
        (n2 (clone MyNumber 'value 20))
        (p1 (clone MyPoint 'x 2 'y 3))
        (p2 (clone MyPoint 'x 4 'y 5)))
    (list1 'AddToList n1)
    (list1 'AddToList n2)
    (list1 'AddToList p1)
    (list2 'AddToList n2)
    (list2 'AddToList p1)
    (list2 'AddToList p2)
    (list2 'AddToList list1)
    (print "list1\n")
    (list1 'Print)
    (print "list2\n")
    (list2 'Print)))