clojure

Jim Newton 2025-11-15T13:52:11.452619Z

can someone tell me what the word “special” means in this documentation of macros in clojure docs? In the Common Lisp specification a “special variable” is a variable which has been bound dynamically. Is that the meaning here? https://clojure.org/reference/macros

Jim Newton 2025-11-17T12:35:38.532449Z

I have some comments to say about &form and &env. Is there a place in the clojure docs wiki Is the best place here? https://clojuredocs.org/clojure.core/defmacro

Alex Miller (Clojure team) 2025-11-17T12:59:33.293089Z

Sounds like a good place to me

✔️ 1
Jim Newton 2025-11-17T13:31:08.220719Z

I don’t know the clojure optional argument syntax very well. Is there a way to pass an optional argument to a macro? For example my macro is defined something like this:

(defmacro rte-case [sequence & clauses] ...)
However, with it is called inside the expansion of another macro, I’d like to pass an additional argument somehow. Do I need to hack this? like use :special-argument as the value of sequence and then pare the argument list myself. yuck. or is there a better way.
`(rte-case :special-argument {:blah 1 :foo 2} ~sequence ~@clauses)

Jim Newton 2025-11-17T13:36:14.140459Z

I’m looking for something like

(defmacro rte-case [sequence &key special-argument & clauses] ...)
and if the macro is called as (rte-case ~my-seq :special-argument foo ~@clauses) then special-argument is bound to the given value.

Jim Newton 2025-11-17T13:36:36.311529Z

There’s something similar in the sh function which special cases the keywords at the end of the argument list.

Jim Newton 2025-11-17T13:38:06.199519Z

(println (sh "ls" "-l"))
(println (sh "ls" "-l" "/no-such-thing"))
(println (sh "sed" "s/[aeiou]/oo/g" :in "hello there\n"))
(println (sh "sed" "s/[aeiou]/oo/g" :in (java.io.StringReader. "hello there\n")))
(println (sh "cat" :in "x\u25bax\n"))
(println (sh "echo" "x\u25bax"))
(println (sh "echo" "x\u25bax" :out-enc "ISO-8859-1")) ; reads 4 single-byte chars
(println (sh "cat" "myimage.png" :out-enc :bytes)) ; reads binary file into bytes[]
(println (sh "cmd" "/c dir 1>&2"))

Alex Miller (Clojure team) 2025-11-17T13:43:00.097869Z

These are typically called kwargs if that helps searching. Use & clauses in the param list. clauses will be a sequence but you can destructure it as if it is a map

Jim Newton 2025-11-17T13:47:24.191949Z

will I be able to use the call-site syntax: (foo :key1 100 :key2 200 clause1 clause2 clause3) Or does the call-site have to consist totally of keyword/value pairs after the first keyword is given?

Alex Miller (Clojure team) 2025-11-17T14:23:27.344819Z

It should consist of key value pairs

✔️ 1
Jim Newton 2025-11-15T13:59:49.114849Z

I’m trying to figure out how to do the following. I have one macro which in its expansion includes another macro call. in the inner macro I need to emit an error message. I could make a much better error message if I had access to the &body of the parent macro expansion. In this example there is an &body of destructuring case which has line-number information about the call-site. However, -destructuring-fn-many is also a macro, and it would like to emit an error message. I could make a much more human readable error message if I had call-site information from destructuring-case

(defmacro destructuring-case
  [expr & operands]
  (cond
    (not= 0 (mod (count operands) 2))
    (throw (ex-info (cl-format false
                               "destructuring-case expects multiple of 2 number of operands after the first:~
                                not ~A, ~A"
                               (count operands) (apply list 'destructuring-case expr operands))
                    {:error-type :invalid-destructuring-case-call-site
                     :expr expr
                     :operands operands}))

    :else
    (let [pairs (partition 2 operands) ]
      `(apply (-destructuring-fn-many nil ~@pairs) ~expr))))

Alex Miller (Clojure team) 2025-11-15T14:22:19.929199Z

The vars &form and &env are "special" because you don't do anything to bind them in the macro definition. Macros are invoked with those 2 "extra" parameters which are provided by the compiler at macroexpansion time

Alex Miller (Clojure team) 2025-11-15T14:23:45.162859Z

a macro does not have access to the surrounding form of it's usage

👍 1
👍🏻 1
Jim Newton 2025-11-15T15:17:10.590959Z

ok, so I could dynamically bind my own copy of &form (and its metadata) to use in the sub macro expansion which is “private” anyway. is that the correct approach, or am I doing something I will regret later?

Jim Newton 2025-11-15T15:18:15.457579Z

or I could even pass it as an explicit parameter to -destructuring-fn-many` since it is private.

Alex Miller (Clojure team) 2025-11-15T16:04:47.336839Z

they are not dynamic vars, so you can't bind them

Alex Miller (Clojure team) 2025-11-15T16:05:00.912589Z

you would need to explicitly pass that info down

👍🏻 1
Alex Miller (Clojure team) 2025-11-15T16:05:45.811869Z

but don't call it &form or &env! those names really are special

😆 3