From 9e77a5972476e0f877c76d7107136fcad42cbc44 Mon Sep 17 00:00:00 2001 From: kovan Date: Sat, 14 Mar 2026 20:00:04 +0100 Subject: [PATCH] Document top-level do behavior When do appears at the top level, each expression is evaluated as a separate top-level form, so side effects like require are visible to the compiler when processing subsequent expressions. This is known as the Gilardi scenario. Fixes #723 --- content/reference/special_forms.adoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/content/reference/special_forms.adoc b/content/reference/special_forms.adoc index 022e31ce..88aa643b 100644 --- a/content/reference/special_forms.adoc +++ b/content/reference/special_forms.adoc @@ -86,6 +86,19 @@ Evaluates _test_. If not the singular values `nil` or `false`, evaluates and yie Evaluates the expressions __expr__s in order and returns the value of the last. If no expressions are supplied, returns `nil`. +When `do` appears at the top level of a file or at the REPL, each expression within it is evaluated as a separate top-level form. This means each expression is fully evaluated before the next one is compiled, so side effects from earlier expressions (such as `require` or `import`) are visible to the compiler when processing later expressions. + +[source,clojure] +---- +;; This works because require is evaluated before set/difference is compiled +(do + (require '[clojure.set :as set]) + (set/difference #{1 2 3} #{1 3})) +;;=> #{2} +---- + +This behavior does not apply to `do` forms nested inside other forms, where the entire enclosing form is compiled before any of it is evaluated. + [[let]] == (`let` [ __binding__* ] __expr__*)