On Mon, Jan 2, 2012 at 2:16 PM, Tassilo Horn <tass...@member.fsf.org> wrote: > nchurch <nchubr...@gmail.com> writes: > > Hi, > >> Someone was asking on the list here about multiple return values, >> which Clojure does not have. >> >> If the facility were ever added, perhaps multiple values could be >> accessed via namespaces. Functions would possess another level of >> namespace and have the ability to inject values into the environment >> under that namespace. For instance: >> >> (defn quotient [x y] >> ..... >> (values quotient remainder)) >> >> (clojure.core/quotient 5 2) >> --> 2 >> clojure.core/quotient/remainder >> --> 1 >> >> This seems simpler than the Common Lisp way. > > I don't think so. And there are several major problems with that > approach. First of all, your clojure.core.quotient/remainder var needs > to be a mutable, thread-local var, because else you couldn't be sure > that 1 is the remainder of the quotient call directly above, or the > remainder of a call that happened a blink later in another thread (or > ForkJoinTask). > > Another problem is that if the var name is determined by the name of the > local var in the function which is given to `values', then changing its > name requires changing all places where clojure.core.quotient/remainder > is used.
On top of all that, how often is this needed anyway where destructuring or metadata can't solve the problem? When performance isn't a concern and you control the calling functions (or they're generic things like map and reduce that just pass the return value through to code you control, such as whatever processes the map sequence output) you can replace something with a vector of that something and additional values, and destructure. And even when you don't control the calling functions, and replacing the return value with a wrapper of any kind would blow up, if that return value is a seq, vector, or other Clojure data type that supports metadata, you can attach metadata (and, to avoid collisions, use namespaced keywords in it) to smuggle the extra values out. In a similar vein, if a non-primitive, non-final Java type is the expected value, you can subclass it with added fields and getters to smuggle out the extra values (the old "decorator pattern") using deftype or reify or proxy. (Some of these don't let you explicitly add fields, but all of them let you define "getters" that close over locals in the function returning them. You'll need a definterface specifying the getters, too.) When the only objection to destructuring is performance, as is likely with your quotient-and-remainder case or similar mathematical-transform cases, there's a final judo move available: continuation-passing. You make the code that was going to *use* the results into a *parameter*, which takes all of the results as arguments. Pre-1.3 you'd probably write something like (defmacro quot-and-rem [a b q r & forms] `(let [a# (long ~a) b# (long ~b) t# (... a# ... b# ...) ~q (...) ~r (...)] ~@forms)) which would execute forms with q and r bound to the quot and rem, respectively, of a and b. Now you can also pass a function expecting two long primitives to a function that takes two long primitives and a function and calls that function with two long primitives, the quotient and the remainder. (The macro approach still gets you the potential benefits and drawbacks of inlining both functions: avoiding the overhead of calls and parameter passing, twice, but also making the current function larger, perhaps large enough to cause cache misses. Obviously it also lets you stay source-compatible with older Clojure versions, for whatever that's worth.) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en