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 "ad...@site.com" "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 pro@common-lisp.net http://lists.common-lisp.net/cgi-bin/mailman/listinfo/pro