Simple protocol implementation for Common Lisp inspired by clojure.
see test.lisp for simple (if somewhat silly) examples. real usage can be seen in the com.clearly-useful.generic-sequence-interface system.
1overview:this system provides a simple implementation of protcols for commonlisp inspired by clojure. the interface to this package isintentionally minimal and exports four symbols:
1.1defprotocolmacrodefprotocol name [docstring] (option | method-declaration)+
where name is a symbol docstring a docstring option is one of: (:require protocol) (:base-method ...) (:eponymous-method t | nil) (:eponymous-generic t | nil)method-declaration isa simple lambda list withan optional docstring (see below)of the options, :require is the most straightforward.the others are a little funky, but have come in handyfor me in practice.options:
- :require other-protocolthis option will check at compile timethat any object implementing this protocolalready implements other-protocol
- :eponymous-generic boolwhen true, defprotocol will generate a genericfunction of one argument with the same name asthe protocol. default is nil.
- :eponymous-method boolwhen true, extend-type will generate a methodwith the same name as the protocol specializingon the implementing type. the method generatedfunctions as identity. this is just a convenienceoption. useage implies (:eponymous-generic t)defaults to nil.
- :base-method ((param) body)when supplied, generates an unspecialized methodwith the same name as the protocol, with the form(:method (param) body). implies (:eponymous-generic t)defaults to nil.
this results in the following:
- definition of the generic function printable, which willfunction as identity for any object implementing thisprotocol. any object which does not implement this protocolwill raise the error "oops!" had a :base-method not beensupplied, a generic not-implemented error would be raised byobjects not implementing the protocol.
- a requirement that any object implementing this protocolalready implement stringable
- definition of the generic function printable-p which testswhether an object implements the protocol printable
- definition of the type printable, which satisfies printable-pwith the documentation "an object which can be printed my way"
- definition of the generic function my-package::print-specialwith the documentation "print object to stream"
note also that methods defined with extend-type only specialize on their first parameter, which is of the type implementing the protocol (see below). this is in line with clojure's implementation, but may not be neccessary for common lisp, as methods are more flexible. a more complex style of definition & implementation of protocols may be implemented in the future to take full advantage of generic function dispatch, but the current simple implementation will continue to work.
1.2extend-typemacroextend-type class-name [protocol-name, method-definition+]+
example: (extend-type string foo (bar (self other) (frob other self)) quux (svelte (self) etc))
performs simple validation at compile time. this will result in method definitions for the generic functions bar and svelte specialized on class string for the first parameter.
lambda-lists for method implementations in extend-type may only contain symbols, and do not support &optional &key &allow-other-keys. this is a limitation of the current implementation that may change in the future. they do, however allow the use of the special symbol _ to indicate ignored parameters. the symbol _ may be used multiple times in an implementation, e.g.
(extend-type frobnicator music:instrument (music:play-with-orchestra (_ _ _) ;;frobnicators only know one note. (music:play-note :b-flat 1.0)))
1.3protocol-extends-class-pfunctionprotocol-extends-class-p protocol-name class-or-class-nametrue if class-or-class-name has implemented the protcolnamed by protocol-name
1.4class-implements-protocol-pfunctionclass-implements-protocol-p class-or-class-name protocol-namesame as above.
1.5notes & todo'sthere is currently no way to undefine a protocol, as I don't knowof a portable way to undefine types in common lisp.
if you redefine a protocol in the current implementation, it does not invalidate existing implementors of the protocol, which would be helpful. This will be fixed.