On Nov 8, 2008, at 8:31 PM, Stuart Halloway wrote:

>
> The defrunonce macro below works, creating a function that runs only
> once and tracking its run status in metadata.
>
> Now, how do I write it without using eval?
>
> (defn runonce
>   "Create a function that will only run once, given a function.  
> Returns
>   a vector containing the function and the reference that tracks
> whether
>   the function has been run."
>   [function]
>   (let [has-run (ref false)]
>     [(fn [& args]
>        (or @has-run
>          ; TODO: think through semantics for parallel target invocation
>          (do
>            (apply function args)
>            (dosync (ref-set has-run true)))))
>      has-run]))

Since the deref of has-run is outside a transaction, I don't see  
anything here that prevents two threads from running function if  
they're trying to do it at roughly the same time.

I think the following version accomplishes the core task of running  
just once and could be adapted to return the has-run ref as well:

(defn runonce
   "Create a function that will only run its argument once."
   [function]
   (let [has-run (ref false)]
     (fn [& args]
       (when
           (dosync
            (ensure has-run)
            (when-not @has-run
              (ref-set has-run true)))
         (apply function args)))))

I'd appreciate seeing corrections or simplifications of it.

--Steve


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to [email protected]
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to