On Thu, 2012-05-31 at 14:50 -0400, Ryan Davis wrote: [...] > I'd like some more opinions on a pattern that has cropped up. One of the > problems we were having was quickly determining what a function expected > for it's arguments. As a somewhat contrived example, SLIME helpfully > would tell me that #'send-email wanted (to from subject body), but then > it was left to me to guess what values I should pass in. In real code > this was frequently non-trivial, and we'd be hand-tracing to figure out > where the parameter was used to figure out what it should be. Should > "to" be a string, a CLOS Client object, or the database ID of a Client? > The answer we arrived at was "yes": > > (defun send-email (to from subject body) > (let ((to (etypecase to > (string to) > ((integer 0) (email (fetch-client to))) > (client (email to)) > ))) > ;; ... more code > )) > > The "to" parameter can be anythings that can be mapped to an email > address. It is send-email's job to send email, and it will figure it out > based on whatever you provide. If it can't do it, it'll tell you. > Usually the etypecase is pulled into it's own function, and we have > something like: > > (defun send-email (to from subject body) > (let ((to (coerce-email to))) > ;; ... more code > ))
I've started using this idiom too: for a type FOO, have, in addition to
the assembling constructor that is make-instance, a coercing constructor
having the same name as the type itself, which can be elided with a
clever use of inlining and type declarations. The CL standard has some
instances of this, e.g. with pathnames: cl:pathname coerces a
pathname-designator(pathnamem, string or file stream) and
cl:make-pathname assembles from components.
Example:
(declaim (inline email))
(defun email (email-designator)
(etypecase email-designator
(string
email-designator)
(unsigned-byte
(email-of (fetch-client email-designator)))
(client
(email-of email-designator))))
(declaim (inline send-email))
(defun send-email (to from subject body)
(let ((to (email to))
(from (email from)))
(%send-email to from subject body)))
(defun send-site-warning (to)
(declare (type string to))
(send-email to "[email protected]" "Warning" "Bandwidth quota reached"))
The creation of the above wrapper - send-email that checks type and
coerces then calls %send-email - can also be easily automated with some
macrology
--
Stelian Ionescu a.k.a. fe[nl]ix
Quidquid latine dictum sit, altum videtur.
http://common-lisp.net/project/iolib
signature.asc
Description: This is a digitally signed message part
_______________________________________________ pro mailing list [email protected] http://lists.common-lisp.net/cgi-bin/mailman/listinfo/pro
