<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Clojure Q&amp;A - Recent questions tagged macroexpansion</title>
<link>https://ask.clojure.org/index.php/tag/macroexpansion</link>
<description></description>
<item>
<title>Macro expansion lose type hints</title>
<link>https://ask.clojure.org/index.php/14740/macro-expansion-lose-type-hints</link>
<description>&lt;p&gt;The following snippet demonstrate how type hints when put before a macro expression are being lost.&lt;br&gt;
On the first expression, the compiler correctly complains about the wrong type hint while it gets accepted if you wrap the hinted expression on a macro. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ clj 
Clojure 1.12.3

user=&amp;gt; (import 'java.util.Date)

user=&amp;gt; (.setHours (Date.) ^long (.getHours (Date.)))
Syntax error (UnsupportedOperationException) compiling fn* at (REPL:1:1).
Cannot coerce int to long, use a cast instead

user=&amp;gt; (.setHours (Date.) ^long (-&amp;gt; (.getHours (Date.))))
nil
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Compiler</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14740/macro-expansion-lose-type-hints</guid>
<pubDate>Mon, 03 Nov 2025 13:50:41 +0000</pubDate>
</item>
<item>
<title>specifying `:let` as the first element of `for` causes an macro expansion error</title>
<link>https://ask.clojure.org/index.php/14670/specifying-let-first-element-causes-macro-expansion-error</link>
<description>&lt;p&gt;We can use &lt;code&gt;:let&lt;/code&gt; in &lt;code&gt;for&lt;/code&gt; to define local variable like this&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(for [i (range 5)
      :let [inc-i (inc i)]]
  [i inc-i])
;;=&amp;gt; ([0 1] [1 2] [2 3] [3 4] [4 5])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise, if we specified &lt;code&gt;:let&lt;/code&gt; as first element, it causes an macro expansion error.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(for [:let [range-end 5]
      i (range range-end)
      :let [inc-i (inc i)]]
  [i inc-i])
;;=&amp;gt; Syntax error macroexpanding for at (*cider-scratch*:555:1).
;;   Can't pop empty vector
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, in this case, we should have wrapped &lt;code&gt;for&lt;/code&gt; in &lt;code&gt;let&lt;/code&gt;. However, I'm curious whether making &lt;code&gt;:let&lt;/code&gt; available only for second and subsequent elements is intended behavior as part of the public interface.&lt;/p&gt;
</description>
<category>Macros</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14670/specifying-let-first-element-causes-macro-expansion-error</guid>
<pubDate>Sun, 10 Aug 2025 02:40:33 +0000</pubDate>
</item>
<item>
<title>defn rejects arity with args vector [&amp;form]</title>
<link>https://ask.clojure.org/index.php/14057/defn-rejects-arity-with-args-vector-form</link>
<description>&lt;p&gt;Here's the smallest case, but it seems to happen no matter how many other arities are provided or whether list or vector syntax is used for the arity.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user=&amp;gt; (clojure-version)
&quot;1.12.0-rc1&quot;
user=&amp;gt; (defn f [&amp;amp;form])
Unexpected error (IndexOutOfBoundsException) macroexpanding defn at (REPL:1:1).
null
user=&amp;gt; *e
#error {
 :cause nil
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message &quot;Unexpected error macroexpanding defn at (1:1).&quot;
   :data #:clojure.error{:phase :macroexpansion, :line 1, :column 1, :source &quot;NO_SOURCE_PATH&quot;, :symbol defn}
   :at [clojure.lang.Compiler macroexpand1 &quot;Compiler.java&quot; 7551]}
  {:type java.lang.IndexOutOfBoundsException
   :message nil
   :at [clojure.lang.RT subvec &quot;RT.java&quot; 1634]}]
 :trace
 [[clojure.lang.RT subvec &quot;RT.java&quot; 1634]
  [clojure.core$sigs$asig__5505 invoke &quot;core.clj&quot; 235]
  [clojure.core$sigs invokeStatic &quot;core.clj&quot; 259]
  [clojure.core$defn__5514 invokeStatic &quot;core.clj&quot; 317]
  [clojure.core$defn__5514 doInvoke &quot;core.clj&quot; 294]
  [clojure.lang.RestFn applyTo &quot;RestFn.java&quot; 149]
  [clojure.lang.Var applyTo &quot;Var.java&quot; 707]
  [clojure.lang.Compiler macroexpand1 &quot;Compiler.java&quot; 7525]
  [clojure.lang.Compiler macroexpand &quot;Compiler.java&quot; 7598]
  [clojure.lang.Compiler eval &quot;Compiler.java&quot; 7684]
  [clojure.lang.Compiler eval &quot;Compiler.java&quot; 7655]
  [clojure.core$eval invokeStatic &quot;core.clj&quot; 3232]
  [clojure.core$eval invoke &quot;core.clj&quot; 3228]
  [clojure.main$repl$read_eval_print__9240$fn__9243 invoke &quot;main.clj&quot; 437]
  [clojure.main$repl$read_eval_print__9240 invoke &quot;main.clj&quot; 437]
  [clojure.main$repl$fn__9249 invoke &quot;main.clj&quot; 459]
  [clojure.main$repl invokeStatic &quot;main.clj&quot; 459]
  [clojure.main$repl_opt invokeStatic &quot;main.clj&quot; 523]
  [clojure.main$main invokeStatic &quot;main.clj&quot; 668]
  [clojure.main$main doInvoke &quot;main.clj&quot; 617]
  [clojure.lang.RestFn invoke &quot;RestFn.java&quot; 400]
  [clojure.lang.AFn applyToHelper &quot;AFn.java&quot; 152]
  [clojure.lang.RestFn applyTo &quot;RestFn.java&quot; 135]
  [clojure.lang.Var applyTo &quot;Var.java&quot; 707]
  [clojure.main main &quot;main.java&quot; 40]]}
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Macros</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14057/defn-rejects-arity-with-args-vector-form</guid>
<pubDate>Mon, 19 Aug 2024 21:05:00 +0000</pubDate>
</item>
<item>
<title>Macro-expansion hooks similar to clojure spec</title>
<link>https://ask.clojure.org/index.php/12956/macro-expansion-hooks-similar-to-clojure-spec</link>
<description>&lt;p&gt;&lt;code&gt;clojure.spec.alpha&lt;/code&gt; currently holds a privileged position as a core library for Clojure core, being able to instrument macros as well as functions. &lt;code&gt;Compiler.java&lt;/code&gt; relies on &lt;code&gt;clojure.spec.alpha&lt;/code&gt; in &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/clojure/clojure/blob/4090f405466ea90bbaf3addbe41f0a6acb164dbb/src/jvm/clojure/lang/Compiler.java#L6967&quot;&gt;this function&lt;/a&gt;, calling &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/clojure/spec.alpha/blob/70f26984ee171f816eee6b162b563d403a49bfe8/src/main/clojure/clojure/spec/alpha.clj#L702&quot;&gt;macroexpand-check&lt;/a&gt; specifically. This is a neat interaction and &lt;code&gt;macroexpand-check&lt;/code&gt; is simple and obvious.&lt;/p&gt;
&lt;p&gt;Other tools (such as Malli) can provide instrumentation for Clojure functions through &lt;code&gt;alter-var-root&lt;/code&gt; (as seen &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/metosin/malli/blob/1a735fe5550b7dccf0832433f2f6d68ce9355edc/src/malli/instrument.clj#L28&quot;&gt;in malli.instrument/-strument!&lt;/a&gt;), but they lack the ability to hook into macro-expansions.&lt;/p&gt;
&lt;p&gt;It would be nice if &lt;code&gt;Compiler.checkSpecs&lt;/code&gt; had some hook to allow for tools such as Malli to be used to instrument macros.&lt;/p&gt;
</description>
<category>Compiler</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/12956/macro-expansion-hooks-similar-to-clojure-spec</guid>
<pubDate>Tue, 23 May 2023 14:18:10 +0000</pubDate>
</item>
<item>
<title>Macro symbols in &amp;env don't get updated when shadowed, still contain the outer symbol instead.</title>
<link>https://ask.clojure.org/index.php/12598/macro-symbols-updated-shadowed-still-contain-symbol-instead</link>
<description>&lt;pre&gt;&lt;code&gt;(defmacro inspect
  [&amp;amp; body]
  (println (keys &amp;amp;env) (map meta (keys &amp;amp;env)))
  `(do ~@body))

(let [^:1 a 1]
  (let [^:2 a 2]
    (let [^:3 a 3]
      (inspect &quot;hello&quot;))))

;;=&amp;gt; (a) ({:1 true})
&quot;hello&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;amp;env&lt;/code&gt; form returns a map of &lt;code&gt;{sym LocalBinding}&lt;/code&gt; and the symbols on the keys of the map are supposed to be the local symbols, but as we see in the above code, when a local symbol is shadowing another, it seems the map does not contain the shadowing symbol, but instead contains the shadowed symbol. We can see that because it is returning the metadata of the outermost symbol, and not the inner one that is shadowing it.&lt;/p&gt;
&lt;p&gt;In my opinion, this is a bug, that said, you can still get at the actual shadowing symbol by calling &lt;code&gt;.-sym&lt;/code&gt; on the LocalBinding, in which case you get the inner shadowing symbol and it will have the right metadata.&lt;/p&gt;
</description>
<category>Compiler</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/12598/macro-symbols-updated-shadowed-still-contain-symbol-instead</guid>
<pubDate>Mon, 30 Jan 2023 03:13:31 +0000</pubDate>
</item>
</channel>
</rss>