On Thu, 5 Aug 2010 16:05:07 +0200 Laurent PETIT <laurent.pe...@gmail.com> wrote: > > My point was that by providing different interfaces/protocols to > different "users", it's more an implementation detail than anything > else if they have the same object or not. I don't expect my users to > program on types, but on protocols/interfaces. > > (ok, in this case, i'm my own user, so I have indeed some expectations > on me ;) ) > > > > > After all I was wrong, it's not a delayed delay I've written. > > > How to rename things ? > > > > > > timed-delay -> ? > > > delay.util.Cancellable -> ? > > > isCancelled -> ? > > > cancel -> ? > > > > timed-delay -> ok > > Cancellable -> Timed > > isCancelled -> countdown-stopped? > > cancel -> stop-countdown > > > > Maybe like this? I dunno. I'm bad at names. :] > > > > > Hm, well .. let's say not worse than me :) >
It sounds like you're having trouble defining what the primitives of your interface are. If I may attempt it, I'll call this construct an "idle speculative cache", i.e. you want to speculatively cache the evaluation some potentially expensive function over an input at a time when the input's value is not changing in a volatile manner, thus avoiding repeatedly and rapidly invalidating cached results of a potentially expensive operation. I can identify three or possibly four useful primitives on an idle speculative cache: (create-isc f timeout inital-input) (update-input! isc x) (deref isc) * 'create returns some opaque thing representing the evaluator, given the function it is to evaluate, the idle timeout for speculative evaluation, and the initial input value. * 'update-input! updates the input value and resets the timeout. * 'deref gets the output value, forcing an evaluation if the cached output is out of date. You might optionally implement another primitive for inspecting the state that does not force, that can either retrieve a possibly-stale result, or retrieve a fresh result and fail if it would require forcing. Given that interface, here's one implementation I came up with: (defn- update-cache [isc] (let [input @(:input isc) new-output-val ((:func isc) (:val input)) new-output {:val new-output-val :ts (:ts input)}] (reset! (:output isc) new-output) new-output-val)) (defn- isc-runner [_ isc] (let [input @(:input isc) quiescent-time (- (System/currentTimeMillis) (:ts input)) sleep-to-go (- (:timeout isc) quiescent-time)] (if (pos? sleep-to-go) (do (Thread/sleep sleep-to-go) (recur nil isc)) (do (update-cache isc) false)))) (defn- deref-isc [isc] (let [output @(:output isc)] (if (= (:ts @(:input isc)) (:ts output)) (:val output) (update-cache isc)))) (defrecord IdleSpeculativeCache [func input output timeout runner] clojure.lang.IDeref (deref [isc] (deref-isc isc))) (defn update-input! [isc x] (reset! (:input isc) {:val x :ts (System/currentTimeMillis)}) (when (not @(:runner isc)) (send-off (:runner isc) (constantly true)) (send-off (:runner isc) isc-runner isc)) nil) (defn create-isc [f in to] (let [isc (IdleSpeculativeCache. f (atom {:val nil :ts 0}) (atom {:val nil :ts 0}) to (agent false))] (update-input! isc in) isc)) This one has one bug I know of, which is that the speculative evaluator ('runner which monitors the i.s.c. input activity) does not check if the output is already fresh due to 'deref forcing before re-evaluating, but I think that could be fixed easily with a test in update-cache. I hope it helps, :) -Kyle -- 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