Re: Idiomatically returning one or two values from a function.

2011-09-30 Thread Daniel Pittman
On Wed, Sep 28, 2011 at 12:15, Daniel Solano Gomez cloj...@sattvik.com wrote:
 On Wed Sep 28 18:52 2011, Daniel Pittman wrote:

 I have problem that I have been thrashing back and forth over the best
 design of for a week now, and I can't work out the nicest way to
 handle it.  Specifically, I have a collection of functions that return
 a primary result, and might also return a secondary annotation about
 that result.

 Why not always return a vector?  That is more or less what a tuple is.

*nod*  Thanks, to you, and the other contributors.  That feels like
the right answer, and I guess I was hung up on not forcing a single
value to be returned in a wrapper so much that I couldn't see it
staring at me.

Daniel
-- 
♲ Made with 100 percent post-consumer electrons

-- 
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


Re: Idiomatically returning one or two values from a function.

2011-09-29 Thread Tassilo Horn
Meikel Brandmeyer m...@kotka.de writes:

 you can return always a vector.

 (fn [] [true])
 (fn [] [true {:foo 12}])

 And then use destructuring on the return value.

 (let [[value annotations] (...)]
   (when annotations
 ..))

My first idea was to add metadata to the return value, but that doesn't
work for java types like Boolean.  As a workaround, you could let your
functions return

(defn foo []
  ;; calculate real-return-val
  (with-meta (constantly real-return-val)
{:foo 1, :bar 2}))

Wrap that in a `annotated-return' macro and always use that in your
functions.  The cost is, that now `foo' returns a function returning the
result, so you have to call it using ((foo)) or (apply (foo))...

But at least you can then do

(let [f (foo)
  r (f)
  m (meta f)]
  ;; the result is r, the metadata is m
  )

Again, wrap that in some `annotated-call' macro, so that you can do

  (annotated-call foo [result meta]
(do-stuff-with result meta))

Hm, but well, that's only a workaround.  Metadata could be so useful if
it was possible to attach it to anything, not only anything in clojure.
I myself once had the need to put metadata on java objects, but that
doesn't work either...

Bye,
Tassilo

-- 
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


Idiomatically returning one or two values from a function.

2011-09-28 Thread Daniel Pittman
G'day.

I have problem that I have been thrashing back and forth over the best
design of for a week now, and I can't work out the nicest way to
handle it.  Specifically, I have a collection of functions that return
a primary result, and might also return a secondary annotation about
that result.

The current implementation is:

(fn [] true) ; primary only
(fn [] (annotated-return true {:foo 12})) ; with annotation

`annotated-return` actually wraps a record, and then the handling code
can determine if the result is specifically that type, or if it is
anything else, to select between the two cases.

In a bunch of other languages I would use a `pair` or `tuple`, but
Clojure doesn't have a native type that maps closely to that.  Worse,
though, it doesn't have a native type that isn't a valid return from
one of these methods.  (Set, Vector, List, and Map are all used. :)

The alternatively I can think of are limited: I don't like the idea of
guessing based on a two element vector return or so, since I want this
to be pretty much impossible to accidentally break.

I considered using meta-data, but that can't attach to a primitive
value, and those are definitely valid results.

So, is there a better way to do this?  At this point I am tempted to
step aside from functional code, and use stateful mutation of some
sort to maintain the annotations:

(fn [] (annotate-by-side-effort {:foo 12}) true)

Daniel
-- 
♲ Made with 100 percent post-consumer electrons

-- 
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


Re: Idiomatically returning one or two values from a function.

2011-09-28 Thread Daniel Solano Gomez
On Wed Sep 28 18:52 2011, Daniel Pittman wrote:
 G'day.
 
 I have problem that I have been thrashing back and forth over the best
 design of for a week now, and I can't work out the nicest way to
 handle it.  Specifically, I have a collection of functions that return
 a primary result, and might also return a secondary annotation about
 that result.
 
 The current implementation is:
 
 (fn [] true) ; primary only
 (fn [] (annotated-return true {:foo 12})) ; with annotation
 
 `annotated-return` actually wraps a record, and then the handling code
 can determine if the result is specifically that type, or if it is
 anything else, to select between the two cases.
 
 In a bunch of other languages I would use a `pair` or `tuple`, but
 Clojure doesn't have a native type that maps closely to that.  Worse,
 though, it doesn't have a native type that isn't a valid return from
 one of these methods.  (Set, Vector, List, and Map are all used. :)
 
 The alternatively I can think of are limited: I don't like the idea of
 guessing based on a two element vector return or so, since I want this
 to be pretty much impossible to accidentally break.

Why not always return a vector?  That is more or less what a tuple is.

(fn [] [true])   ; primary only
(fn [] [true {:foo 12}]) ; with annotation

That way, your data is always (first x) and your metadata is always
(second x).

If you want to use something more typed-like, you could return a map:

(fn [] {:result true})
(fn [] {:result true :metadata {:foo 12}})

For this approach, you could write helper functions to make the code
less painful to read and write.  If performance is a concern, you can
try a record.

 I considered using meta-data, but that can't attach to a primitive
 value, and those are definitely valid results.
 
 So, is there a better way to do this?  At this point I am tempted to
 step aside from functional code, and use stateful mutation of some
 sort to maintain the annotations:
 
 (fn [] (annotate-by-side-effort {:foo 12}) true)
 
 Daniel
 -- 
 ♲ Made with 100 percent post-consumer electrons
 
 -- 
 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


signature.asc
Description: Digital signature


Re: Idiomatically returning one or two values from a function.

2011-09-28 Thread Meikel Brandmeyer
Hi,

you can return always a vector.

(fn [] [true])
(fn [] [true {:foo 12}])

And then use destructuring on the return value.

(let [[value annotations] (...)]
  (when annotations
..))

Sincerely
Meikel

-- 
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