com.clearly-useful.protocols

2013-03-12

Simple protocol implementation for Common Lisp inspired by clojure.

Upstream URL

github.com/jaeschliman/com.clearly-useful.protocols

Author

Jason Aeschliman <j.aeschliman@gmail.com>

License

revised BSD
README
simple clojure-style protocols for common lisp

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.1defprotocol

macrodefprotocol 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.
example:(defprotocol printable"an object which can be printed my way"(:base-method (object) (error "oops!"))(:require stringable)(my-package::print-special (object stream) "print object to stream"))

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 that the lambda list for a protocol method is restricted tosymbols, and may not contain &optional &key&allow-other-keys. this is to simplify the validation of protocoldefinitions & implementations at compile time, and may be changedin the future.

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-type

macroextend-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-p

functionprotocol-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-p

functionclass-implements-protocol-p class-or-class-name protocol-namesame as above.

1.5notes & todo's

there 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.

1.5.1TODOfix protocol redefinition

1.5.2TODOadd extend-protocol

1.5.3TODO[#A] add ability to extend objects as well as types

1.5.4DONEerror messages are less helpful than they could be at the moment.

1.5.5TODOmigrate to a proper test framework

Dependencies (1)

  • iterate
  • GitHub
  • Quicklisp