This is my first venture into macros since starting with Clojure a bunch of years ago - no urge here. I also use binding for a use-case I haven’t seen any other solution for; an implementation of a protocol which doesn’t take a tx as a parameter but wants to participate in a tx. Binding is a perfect fit for that.
I think we agree entirely and I think I maybe misled with the use-case I was apparently proposing using a macro for :-). My question was more about _how_ do I get this to work rather than _should_ I do it this way. Thanks again Thomas. > On 2 Oct 2015, at 15:48, Thomas Heller <th.hel...@gmail.com> wrote: > > Well, yeah .. don't use binding. Sometimes they are a good solution though, > so don't forget about it. > > Again I do not know your future plans. I would always recommend writing > everything with data+functions first. If you find that you have written the > same thing over and over again it might be time to introduce a new function > OR actually a macro if that doesn't work. > > Macros sure are extremely powerful, so figuring out exactly when to use them > is quite hard. I know that it took me quite some time to get rid of the "hey, > just use a macro" urge. > > Anyways, glad we agree that your initial macro does not need to exist. ;) > > cheer, > /thomas > > On Friday, October 2, 2015 at 4:15:47 PM UTC+2, Colin Yates wrote: > Hi Thomas, binding - really? :-). Apart from the general negative reaction > they seem to have, I don’t want the individual elements (e.g. text and > number) to assume rely on the binding as they can be called individually as > well and the binding would just get in the way. > > My understanding is that if I want to change a call to a function _before_ > that call happens then my only option is to use a macro? > > (I also realise this use-case will never need a macro as hiccup very sensibly > uses data so the thing passed to (form) is simply a vector.) > > I am saying, the discussion of whether _this example_ justifies a macro is > mute - I agree it doesn’t. > >> On 2 Oct 2015, at 15:01, Thomas Heller <th.h...@gmail.com <javascript:>> >> wrote: >> >> Well, if you don't like that 'form' you could use a binding. >> >> (binding [form/*state* >> {:editing? true >> :values form-values >> :validation validation-report >> :on-change handle-form-change}] >> (form/tag >> (form/text :name) >> (form/number :age))) >> >> Anyways, I would not recommend using the binding but doesn't mean you can't. >> >> I can't quite imagine what your future plans look like but you probably >> won't need a macro. ;) >> >> cheers, >> /thomas >> >> On Friday, October 2, 2015 at 3:34:48 PM UTC+2, Colin Yates wrote: >> Hi Thomas - yes, you are right. The example I provided is all pain/no-gain >> in terms of macros. However, future plans will require manipulating the >> invocation of (for example form/text and form/number) before they are >> evaluated. >> >> Having said all of that, that repeated ‘form’ does bug me a bit :-). I do >> absolutely agree that the cognitive overhead of the macro isn’t justified >> here. >> >>> On 2 Oct 2015, at 14:29, Thomas Heller <th.h...@ <>gmail.com >>> <http://gmail.com/>> wrote: >>> >>> Have you tried NOT using a macro at all? This code does not need to be a >>> macro at all if you ask me. >>> >>> Just a little sketch but things could look just about the same without any >>> macros at all: >>> >>> (let [form {:editing? true >>> :values form-values >>> :validation validation-report >>> :on-change handle-form-change}] >>> (form/tag form >>> (form/text form :name) >>> (form/number form :age))) >>> >>> >>> ;; in-ns 'form >>> >>> (defn text [form field] >>> [text-component {:id field >>> :value (get-in form [:values field]) >>> ...}]) >>> >>> (defn tag >>> [{:keys [editing?] :as form} & children] >>> (into [:div.form.horizontal >>> {:class (if editing? "editing" "editable")}] >>> children)) >>> >>> >>> Use macros very sparingly, most of the time data and functions are just >>> better. >>> >>> Just my 2 cents, >>> /thomas >>> >>> On Wednesday, September 30, 2015 at 10:29:30 PM UTC+2, Colin Yates wrote: >>> Hi all, >>> >>> I am banging my head against the wall - I think it is obvious but I have >>> started too long: >>> >>> The use-case is that I want a form which takes a set of children. The form >>> also takes in some form-wide state, like the form-wide validation, the >>> values for each item etc. I want the macro, for each child, to decorate >>> that child by extracting the validation errors and value from the form-wide >>> state. >>> >>> So, assuming: >>> - validation looks like {:name "Duplicate name" :age "You must be at least >>> 0"} >>> - form-values looks like {:name "a-duplicate-user" :age -1} >>> >>> then my form might look like: >>> >>> (form {:editing? true :values form-values :validation validation-report >>> :on-change handle-form-change} >>> [form/text {:id :name}] >>> [form/number {:id :age}]) >>> >>> After the macro I want the following code: >>> >>> [:div.form.horizontal >>> {:class "editing"} >>> [form/text {:id :name :value "a-duplicate-user" :errors "Duplicate name" >>> :on-click (fn [e] (handle-form-change :name (-> e .target .value])] >>> [form/number {:id :age :value "-1" :errors "You must be at least 0" >>> :on-click (fn [e] (handle-form-change :age (-> e .target .value))]] >>> >>> However, ideally the macro would _not_ emit the contents of the input as >>> literals but would emit code that inspects the provided parameters at >>> run-time (i.e. rather than :value "a-duplicate-user" I would much prefer >>> :value (-> state values :name) as that will allow me to pass in an atom for >>> example. >>> >>> I have tried so many variations and evaluating the state (e.g. (:editing? >>> state)) works fine as the emitted code has the destructured values, but >>> that doesn't work for an atom. >>> >>> Here is my attempt at trying to emit code that interrogates the provided >>> parameter. >>> >>> (defmacro form [state & elements] >>> (let [state# state] >>> `[:div.form.horizontal >>> {:class (if (:editing? state#) "editing" "editable")} >>> ~@(map (fn [[_ {:keys [id]} :as child]] >>> (update child 1 assoc >>> :editing? (:editing? state#) >>> :value `(-> (:values state#) 'deref (get ~id)) >>> :on-change `(fn [e#] >>> (js/console.log "E: " >>> (cljs.core/clj->js e#)) >>> ((:on-change state#) ~id (-> e# >>> .-target .-value))))) >>> elements)])) >>> >>> The error I am getting is that there is such var as the gen-sym's state# in >>> the namespace. >>> >>> The generic thing I am trying to do is remove the boilerplate from each of >>> the items in the form. >>> >>> Any and all suggestions are welcome. >>> >>> Thanks! >>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To post to this group, send email to clo...@ <>googlegroups.com >>> <http://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+u...@ <>googlegroups.com <http://googlegroups.com/> >>> For more options, visit this group at >>> http://groups.google.com/group/clojure?hl=en >>> <http://groups.google.com/group/clojure?hl=en> >>> --- >>> You received this message because you are subscribed to the Google Groups >>> "Clojure" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to clojure+u...@ <>googlegroups.com <http://googlegroups.com/>. >>> For more options, visit https://groups.google.com/d/optout >>> <https://groups.google.com/d/optout>. >> >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@googlegroups.com <javascript:> >> Note that posts from new members are moderated - please be patient with your >> first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com <javascript:> >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> <http://groups.google.com/group/clojure?hl=en> >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+u...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/d/optout >> <https://groups.google.com/d/optout>. > > > -- > 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 > <http://groups.google.com/group/clojure?hl=en> > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com > <mailto:clojure+unsubscr...@googlegroups.com>. > For more options, visit https://groups.google.com/d/optout > <https://groups.google.com/d/optout>. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.