hi,

apologies if this is a long question, i would appreciate some guidance here.

i am creating a clojure wrapper around a rather verbose low latency
messaging framework. the main things you can do are publish messages,
receive messages, initialize sources and receivers etc. all are done
through a 'context'. i have ended up with this (silly example):

(with-context [:some "parameter"]
  (init-receiver "some-topic" :some "option")
  (init-source "some-topic" :on-disconnect #(println "client disconnected"))
  (publish "some-topic" "some-message" :other "option")
  (receive "some-topic"
           (fn [o m] (println "received: " (.dataString m)))))

which i am fairly happy with. it is all wrapping up access to
underlying java objects (eg a context object, lists of sources,
receivers, threads and so on).

the implementation (somewhat simplified for clarity) is like:

;; these will be bound later
(def init-receiver nil)
(def init-source nil)
(def publish nil)
(def receive nil)

;; real impls with more args than i want to have to pass around
(defn init-receiver-on [context receivers topic] ...boring java stuff)
(defn init-source-on [context sources topic] ...boring java stuff)
(defn publish-on [context sources topic message] ...boring java stuff)
(defn receive-on [context receivers topic func] ...boring java stuff)

(defmacro with-context [options & body]
  `(let [context# (create-context options)
         thread# (create-thread context)
         sources# (atom {})
         receivers# (atom {})]
     (binding [init-receiver (partial init-receiver-on context# receivers#)
               init-source (partial init-source-on context# sources#)
               publish (partial publish-on context# sources#)
               receiver (partial receive-on context# receivers#)]
       (try
         (do ~...@body)
         (finally
           ... close stuff, cleanup)))))

so i am binding those functions to partial applications which use the
lexically scoped context, thread etc when you use the macro. is this
reasonable?

a prior implementation i had was like:

(defmacro with-context [options & body]
  `(let [context# (create-context options)
         thread# (create-thread context#)]
         sources# (atom {})
         receivers# (atom {})]
    (letfn [(~'publish [topic# msg# & options#] (publish-on context#
sources# topic# msg# options#))
            (~'receive [topic# callback# & options#] (receive-on
context# receivers# topic# callback# options#))
            (~'init-source [topic# & options#] (init-source-on
context# sources# topic# options#))
            (~'init-receiver [topic# & options#] (init-receiver-on
context# receivers# topic# options#))]
         (try
           (do ~...@body)
           (finally
            ... cleanup))))))

which seems like a bit of an abuse, creating an anaphara for each of
the functions. the problem i had with this was the anaphara werent
available when i was outside of my macro (eg in any other function
called from the macro):

(defn start-server [] (receiver "topic" (fn [o m] (println "this is
full of fail"))))
(with-context [] (start-server))

i also tried implementing it using a protocol and reify, which worked
rather well and felt the 'cleanest' solution, the impl of which is
probably fairly obvious so i wont bother typing it in here. however i
didnt like having to pass an object around everywhere to call methods
on.

my question is simply, what is the most idiomatic solution? im
guessing the protocol and reify, but is the first solution also
reasonable?

again, sorry for the long question - i also typed it all from memory
so apologies for any obvious typos / mistakes, i dont have the code
available on the machine i am using. any insight would be appreciated.

thanks,

gareth

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