On 21 February 2010 13:47, Michał Marczyk <michal.marc...@gmail.com> wrote:
> On 21 February 2010 09:37, Michael Wood <esiot...@gmail.com> wrote:
>> (defn print-info []
>>  (let [[src dst] (dosync
>>                    (ensure source-account)
>>                    (ensure dest-account)
>>                   �...@source-account @dest-account])]
>>    (println src)
>>    (println dst)))
>
> This can be simplified to
>
> (defn print-info []
>  (let [[src dst] (dosync
>                        [(ensure source-account)
>                        (ensure dest-account)])]
>    (println src)
>    (println dst)))
>
> ensure returns the in-trasaction value of the ref.

Ah, thanks.

> There's no guarantee that the refs won't be changed a split second
> after the transaction, of course...

Of course.

> To demonstrate the difference between a simple @r and (ensure r) in a
> transaction, define the following ref & function at the REPL:
>
> (def r (ref 1))
>
> (defn funk [r]
>  (dosync
>   (let [v (ensure r)]
>     (println v)
>     (Thread/sleep 5000)
>     (println v))))
>
> Now launch it in a separate thread:
>
> (.start (Thread. #(funk r)))
>
> It'll print a "1" straight away, but you'll have a moment to type in
> another expression before it proceeds with the second println. So, do
> this:
>
> (dosync (ref-set r 5))
>
> Notice that this blocks until the second println happens, then resets
> the value of the ref afterwards.
>
> With (ensure r) replaced by @r in the definition of funk, the (dosync
> (ref-set r 5)) would succeed and the funky transaction would retry,
> thus performing three printlns in total.

That does demonstrate the difference (or a difference), but I don't
get 3 printlns.

I modified the printlns to distinguish between the two:

(defn funk [r]
 (dosync
  (let [v @r]
    (println "Start:" v)
    (Thread/sleep 5000)
    (println "End:" v))))

I assume you were expecting something like:
user=> (.start (Thread. #(funk r)))
Start: 1
nil
user=> (dosync (ref-set r 5))
5
user=> Start: 5
End: 5
?

What I see is:
user=> (.start (Thread. #(funk r)))
Start: 1
nil
user=> (dosync (ref-set r 5))
5
user=> End: 1

This is with Clojure 1.2.0-master-SNAPSHOT
(2855e34106b2cacd4614f2b7e31f1536b4b849bc)

> Thus using ensure may actually make in-transaction side-effects safe
> at the cost of some lost concurrency.

-- 
Michael Wood <esiot...@gmail.com>

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