Object oriented programming =========================== OOP in Antilisp relies on two independant abstractions: generics and classes Generics are polymorphic functions with runtime multiple dispatch over the types of their arguments. The dispatched definitions of a generic are called methods. Classes allow the user to define their own types and inherit methods and attributes defined on parent classes. Generics -------- Generics are defined with ``(defgeneric)``, and implemented with ``(defmethod)``: :: (defgeneric (to-list x)) # default implementation: raise an error (defmethod (to-list x) (error "undefined-method" (+ "to-list is not defined for " (repr x)))) # define to-list for strings # the last definition has higher priority over the previous ones (defmethod (to-list (x string)) # convert the string to a list of characters # ... '()) Methods are stored in the method-store global dictionary. Classes ------- Antilisp provides primitive OOP constructs to manipulate objects: :: (make-class parent-classes ...attributes) # create and return a class (make-instance class) # create and return an instance of class (get-attr object 'attribute) (set-attr object 'attribute value) (is-instance object class) # reflection (is-subclass class-1 class-2) (get-class-attributes class) (get-class-env class) (get-type object) However, the recommended way of using objects is with the ``(defclass)`` macro: :: ; the defclass macro automatically defines a constructor (make-vector), a type predicate (is-vector) and a generic type cast (to-vector) (defclass vector () "a 2D vector class" x y) (let v (make-vector 1 2) (set (x v) 3) (print (x v))) ; prints 3 (defmethod (length (x vector)) ; TODO 0) (defmethod (to-vector (x cell)) (make-vector (car x) (car (cdr x)))) (let v (make-vector 1 2) (print (is-vector v))) ; the class docstring is parsed by defclass to set the docstring (print (get-doc vector)) ; "a 2D vector class" Generic casts and type predicates have been defined for builtin types as well: :: (to-symbol (+ "to-" (to-string 'vector))) # 'to-vector (is-integer 0) (is-string "string") (is-symbol 'variable) Many builtins, like ``(repr)``, ``(at)`` or ``(iter)``, are implemented as generics. A special case is ``(+)``, which can accept any number of arguments, and internally uses the ``(add)`` generic to add with type dispatch.