Your reply has saved me from worrying about necro'ing this thread!

Always return multiple values unless your function's clients (if it has no clients why does it exist?) would always want to create a composite type to hang onto them.
You said that you found dealing with multiple values 'awkward' but didn't make it explicit as to which aspect of MULTIPLE-VALUE-BIND you didn't like. I see the following things that you might dislike:
- length of its name
- length of its name leading to long lines (especially once you have to bind a lot of different values)
- increased indenting from interleaved LET, LET*, MULTIPLE-VALUE-BIND, DESTRUCTURING-BIND, WITH-SLOTS, etc when binding temporary variables
The first merely requires getting tab-completion activated in your editor of choice. I'm not an 'only emacs will do' zealot, but I haven't gotten further than doing 1-line edits in vim, so I can't help you with that.
The second can be a grey area, I personally still wouldn't return a composite type for less than 7-10 results (unless a composite type was called for).
The third isn't a reason not to use multiple values, it's a reason not to use MULTIPLE-VALUE-BIND (directly). A 5-minute macro to unify the syntax:
- Code: Select all
(defmacro bind ((&rest bindings) &body body)
(setf body `(locally ,@body))
(let (let-bindings)
(labels ((add-let-binding (binding)
(push binding let-bindings))
(emit-let-bindings ()
(when let-bindings
(setf body
`(let* ,let-bindings
,body))
(setf let-bindings nil))))
(dolist (binding (reverse bindings))
(if (listp binding)
(case (first binding)
(:mv
(emit-let-bindings)
(setf body
`(multiple-value-bind ,(second binding) ,(third binding)
,body)))
(:db
(emit-let-bindings)
(setf body
`(destructuring-bind ,(second binding) ,(third binding)
,body)))
(t
(add-let-binding binding)))
;; else
(add-let-binding binding)))
(emit-let-bindings)))
body)
Which you might use like:
- Code: Select all
(bind (nil-variable
(variable-with-initialiser 1)
(:mv (quotient divisor) (floor 5 2))
(:db (a b (c d) e) '(f g (h i) j)))
(declare (ignore ...))
...)
This handles LET*, MULTIPLE-VALUE-BIND, and DESTRUCTURING-BIND, and I would hope you could easily see how to extend it to others. There's a number of things that you might want to customise about this macro, or you could find a library with a different macro (I know that there's at least one, but I can't remember where I saw it).
The important (and delightful) thing about lisps is that, unlike blubs, you are only as far away from a convenient solution as your ingenuity and imagination!
