[pro] style question about types, coercion, expectations for function parameters
Stelian Ionescu
sionescu at cddr.org
Thu May 31 19:45:28 UTC 2012
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 "admin at 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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part
URL: <https://mailman.common-lisp.net/pipermail/pro/attachments/20120531/0e45f9f2/attachment.sig>
More information about the pro
mailing list