This is a really neat macro, but would people want to rewrite their
programs in continuation-passing style just to be able to return
multiple values sometimes? (And a macro is not a first-class
entity.) Of course, much of the time, the easiest thing to do \is to
return a vector or some other destructureable object. But this
changes the interface: the function no longer directly returns a
singular value. Metadata avoids this problem, but doesn't work on
numbers, among other things. So there really are cases where having
multiple return values would help (when you want a function to give
you one value unless you want more)----preferably without judo!
(altough judo is great too.)
Replying to Tassilo: I'm not quite sure I understand this problem:
> then changing its
> name requires changing all places where clojure.core.quotient/remainder is
> used
surely the call to Values takes place inside the function definition,
which happens \once. If you want a different variable name on \use,
you use a let; if you want to return a different variable name on
\definition, you use a let inside the function (or perhaps Values
could have some sugar for renaming variables).
It's true that quotient/remainder must be thread-local (in fact it
should really be function-local), but this makes it no different than
a let-variable or a function parameter; it doesn't necessarily mean it
is mutable. Is X mutable in
(let [X 1
X (inc X)])
?
If you slapped that X in a data structure, you would not find it
changing under your nose. quotient/remainder really has to behave in
the same way----imagine the quotient call creates an invisible let
every time.
Perhaps I should explain why I think this is "simple". It's simple
because a) it allows you to ignore the extra values unless you want
them and b) it gives you ready-to-use names. To my taste, b) is very
important. One of the reasons I dislike OOP is all the boilerplate
like
this.x = x.
But how many times do you have to write
(let [x (some-expensive function ... )....]
just so you can use the returned value more than once? What we would
do here is write
some-expensive-function/
the next time we want to use the value (assuming this is the notation
for getting the \default value)----so in this case we don't even \care
about multiple return values.
If we think of this as a name-generating facility that happens to
handle multiple values, we could imagine extensions to it for
distinguishing more values----
(quotient 5 2)
(quotient 8 3)
quotient(5 2)/remainder --> 1
(rand(1) 12)
(rand(2) 12)
rand(1)(12)/
This is all rather fanciful, and admittedly a huge extension to the
language; but what's the harm in thinking about these things?
The next time you are telling your kids a bedtime story, you might
start as follows:
"A man ate some soup. The man was bald, and the soup had an unhappy
grasshopper in it. The grasshopper...."
Scratch that: you should tell it as follows:
Let there be a man my-man, and some soup my-soup, and a grasshopper my-
grasshopper. my-man ate some of my-soup. my-man was bald. my-soup
had my-grasshopper in it. And my-grasshopper was unhappy....
This makes for earlier bedtimes but worse storytelling.
On Jan 3, 12:36 am, Cedric Greevey <[email protected]> wrote:
> On Mon, Jan 2, 2012 at 2:16 PM, Tassilo Horn <[email protected]> wrote:
> > nchurch <[email protected]> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en