Welcome! Please see the About page for a little more info on how this works.

0 votes
ago in Compiler by
closed ago by

when a let or fn body begins with the bare symbol do (not in list head position) it is treated as a do-block wrapper for the rest of the body

Clojure 1.12.0
user=> (let [] do)
nil
user=> (let [] do 123)
123
user=> (let [] 123 do)
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: do in this context
user=> ((fn [] do))
nil

Aside from being unexpected, it also has the effect of appearing to override any local binding named 'do':

user=> (let [do :something] do)
nil

Note that Clojurescript treats all the above cases 'correctly':

ClojureScript 1.11.132
cljs.user=> (let [] do)
                    ^
WARNING: Use of undeclared Var cljs.user/do at line 1
nil
cljs.user=> (let [do :something] do)
:something

The community guide at https://clojure-doc.org/articles/language/macros/
has pointed out this exact edge case (since 2013?) and recommends to 'Never use special names as local binding or global variable names'. However it seems like a bug worth addressing given the discrepancy between JVM/CLJS outputs

ago by
Ah, seems like this has already been reported before (sorry for the dupe, a search didn't turn these up at the time)

https://clojure.atlassian.net/browse/CLJ-1216

and more recently

https://ask.clojure.org/index.php/1197/the-do-symbol-is-skipped-in-some-contexts-where-it-shouldnt-be
...