this is the difference between let and do: For toplevel do forms, the body is hoisted up and compiled and executed each one at a time.
So for
(do
(.setDynamic #'v true) ;1
(binding [v :new] ;2
(println v))
(.setDynamic #'v false) ; 3
)
The expression is broken up into the three expressions
(.setDynamic #'v true) ; 1
.
(binding [v :new] ; 2
(println v))
.
(.setDynamic #'v false) ;3
And each expression is then compiled and executed one after the other. Which means the effect of executing expression #1 is visible when compiling expression #2
And the dynamic check for a var happens at compile time, not at runtime, so expression #1 running means that the reference to v in expression #2 is compiled differently to handle a possibly rebound var.
For let expressions, the entire expression is compiled and then executed at once. So when #2 is compiled, #1 hasn't been executed yet, so the var is not marked as dynamic, so the code for handling a bound var is not emitted by the compiler.