delay/force definitely do not do what I'm describing. What we want to is something like a continuation as mentioned by Chouser. We want to block the thread of execution until some point in the future when the values become available.

I'm not sure that what you described describes what you want :)

Yes, if you want to block the current thread to wait for a value computed by a background thread, you need promises and futures.

However, you were explicitly talking about a use "outside the context of concurrency". If you don't want concurrency, only delayed execution, then use delay instead.

In your example you have to *know* that all the tests have run in order to accumulate results.

No you don't — force is synchronous. By the time that `doall` has finished, all the tests have run and their results have been accumulated inside the delays.

As I said, if you want to run tests in parallel, then you're not talking "outside the context of concurrency". Futures are awesome, but you can't argue that they're not a parallel construct.

By using promise/deliver you can remove yourself from caring about that at all.

With a recursive data structure this becomes annoying very quickly, you have to bookkeep where you are if you use delay/force.

No you don't — simply always call `force`, just as you always call `deref`, and the delayed computation will be done if necessary. (In fact, you can use "@", just as you can with refs and promises.)

Here's an example of a trivial recursive arithmetic evaluator that prints the whole tree, returning a delay which captures the execution. When forced, it prints the arithmetic results back up the tree. Execution occurs once.

(defn form->delay [v]
  (if (number? v)
    (do
      (println "  Saw number" v)
      (delay v))
    (let [[op & args] v]
      (println "Seen form with operator" op ", args" args)
      (let [delays (map form->delay args)]
        (delay
          (let [res (eval `(~op ~@(map force delays)))]
            (println "Result is" res)
            res))))))

user=> (let [de (form->delay `(+ 5 (- 3 2)))]
  (println "First run: " @de)
  (println "No bookkeeping: " @de)
  (println "Delay: " de)
  @de)

Seen form with operator clojure.core/+ , args (5 (clojure.core/- 3 2))
  Saw number 5
Seen form with operator clojure.core/- , args (3 2)
  Saw number 3
  Saw number 2
Result is 1
Result is 6
First run:  6
No bookkeeping:  6
Delay:  #<de...@58e22f2b: 6>
6


You'll see that:

* It runs on one thread
* There is no bookkeeping of what's been forced and what has not; you can force multiple times without re-execution * It can do arbitrary work during the tree walk (printing "Seen form..."), and during evaluation (printing "Result is"), and the two phases are separate.


By creating the future computations to be performed during the traversal you later only need to deliver each individual test result. As tests come in they automatically trigger the next level of computation (the aggregate result). You don't need track relationships between tests at all because that was determined by the first traversal.

There are only two places where futures might apply in what you're talking about:

* To run tests in parallel, which you explicitly disregarded
* To have the tests depend on each other's values (which doesn't seem very smart to me).

Use futures and promises for parallelism or dataflow-style work. Use delay for non-parallel, synchronous delayed execution.

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

Reply via email to