More generally, I had an aha-moment when closures were restated as behaviour that hold on to some state — an inversion of how most of us OO-language users think. This fits very well with my renewed understanding of closures as “closing over” a bunch of state — closed over vars do not go out of scope while the closure is alive. That local vars went out of scope once the function/method completed in many languages, in retrospect, has been the main thing that stopped me from fully “getting” closures when I first looked at it. Then again, it is a subtlety that I had failed to fully appreciate even in Java which does have limited closure support via returning class instances from functions that can reference local vars, so long as they are marked final. By implication, the objects referenced by those vars do not go out of scope whilst the class instance returned holding on to them is alive.
Second satori: As stated above, “the elegance and hackery of building sophisticated things from a small, composable featureset is very neat”, but the syntax is annoying — a language with macro facilities (various LISPs), provides both this composable core, and a unified, extensible syntax. Pretty amazing. In case of LISP, non-syntax really. If only I could get used to the gazillion parentheses of LISP.
Somewhat less elegant than macros (but I love the idea nevertheless) is Groovy‘s parser/compiler hooks which essentially allow you to transform your own syntax/constructs into plain ol’ Groovy at various compilation phases of the program. This is how Groovy allows arbitrary DSLs that do not fit its grammar, a famous example being the Spock Testing Framework.