;;;; To Do add-pushes? Two-pass sequence construction? Make sure (make ) corresponds to design note 03. #6: Limited Types (Addition) #7: Union Types (Addition) #8: Method Dispatch Ambiguity (Clarification) #25: Exit Extent (Change) #26: New Iteration Protocol (Change) #31: Method Specificity (Change) #37: Variadic Operators (Change) Pick up Pierce's new ranges. Incorporate design note 29's changes to RANGE and (MAKE ...). ;;;; Issues re: hooking into the type system. Need a BOOLEAN class. ;;;; Dylan in Python METHODS: Methods have two external entry points: an anonymous entry point and a generic-function entry point. Methods are represented by a funcallable- instance. The funcallable-instance's function holds the anonymous entry point, and one of the instance-slots holds the generic-function entry point (as a regular function). If we didn't care about performance, methods could be constructed by doing: (make-builtin-method :debug-name ... :specializers (list ...) :function #'gf-entry) But if all the specializers are compile-time constants, we can do much better then that. First off, we probably want a custom anonymous entry point: (install-dispatch-function (%make-builtin-method ....) #'(lambda (a b c ...) (check-type a ) (check-type b ) (check-type c ) (gf-entry a b c ...))) We still need to build the builtin-method fin complete with specializer list so that this method can be added to generic functions. [Actually, we probably want methods with custom anonymous entry points and methods with the default anonymous entry point to have different types.] If the method is being local-called, then we can do even better. We just propagate the specializers (i.e. type assertions) to the args: (gf-entry (the a) (the b) (the c) ...) #NEXT, NEXT-METHOD There is a lot of magic hidden behind the NEXT-METHOD method parameter. Specifically, NEXT-METHOD encapsulates the entire list of additional methods in addition to the list of original arguments. If we assume that the XEP function is really passed a list of the additional methods as if it were: (lambda (nargs more-methods arg0 arg1 ... argn) ...) then NEXT-METHOD gets expanded in one of the following manners: next-method => (if more-methods #'(lambda (&rest args) (if args (apply (car more-methods) (cdr more-methods) args) (funcall (car more-methods) (cdr more-methods) arg0 arg1 ... argn))) #f) (next-method) => (if more-methods (funcall (car more-methods) (cdr more-methods) arg0 arg1 ... argn) (error "No more methods")) (next-method narg0 narg1 ... nargn) => (if more-methods (funcall (car more-methods) (cdr more-methods) narg0 narg1 ... nargn) (error "No more methods")) Things would work if we always used the first translation, but the problem with that is that then we would end up with an expression looking like: (funcall (if more-methods #'(lambda (&rest args) (if args ...)) #f) narg0 narg1 ... nargn) The if being inside the funcall might make it difficult to know the outcome of the inside if even though the information is there. Otherwise, the &rest arg could be optimized away by passing the nargs directly in. BIND-EXIT Bind-exit is trivial. It just expands into: (block #:g1 (flet ((exit (&rest args) (return-from #:g1 (values-list args)))) (declare (inline exit)) ...)) If someone references exit as a function, it will be inlined, resulting in a direct return-from. If they reference it as a value, it will just work out.