Earlier quoted context omitted.
It seems to me that what you've demonstrated is that side effects are possible in Clojure, esp. with sufficiently obfuscated (read: un-idiomatic) code. But you're working too hard anyway; Clojure explicitly admits mutability already, through various concurrency pieces like atoms and refs. That said, if any admission of mutability is sufficient to disqualify a language from claiming to encourage or support referential…
I should have known that my poor knowledge of lisp would not be excused on HN ;-) Anyway, I tried learning enough clojure to prove that routine metaprogramming would often be not referentially transparent. First, note from the wikipedia page that "referentially transparent" essentially means that the same function with the same arguments will always produce the same result, and that you can call it more (throwing awa…
The issue is invoking "(swapargs (mod 7 5))". I tried this in the Scheme REPL (Chicken to be precise), in which the macro was defined:
(define-syntax swapargs
(syntax-rules ()
((_ ls) (list (list-ref ls 0) (list-ref ls 2)
(list-ref ls 1)))))
(swapargs '(a b c)) => (a c b)
(swapargs (swapargs '(a b c))) => (a b c)
In other words, the macro does show referential transparency.However, the following doesn't work:
(swapargs (modulo 7 5)) => Error: (list-tail) bad
argument type: 2
The problem is the argument is evaluated first, and "2" is not a list. (The macro requires a list-of-3 argument.) (modulo 7 5) => 2
Probably, what was intended was like this: (swapargs '(module 7 5)) => (modulo 5 7)
And again: (swapargs (swapargs '(module 7 5))) => (module 7 5)
(eval (swapargs '(module 7 5))) => 5
(eval (swapargs (swapargs '(module 7 5)))) => 2
(eval (swapargs (swapargs '(module 10 8)))) => 2
It looks like confusion between literal and evaluable lists prompted the wrong conclusion, but in this case it's simple to rectify.Of course, macros in Scheme/Lisp can easily become convoluted and bug-ridden as much as any code, even aside from arguments about the virtues of "hygienic" vs. "unhygienic" systems. Properly constructed, macros remain an essential feature of Lisp/Scheme languages.
BTW, if we're comparing qualities of programming languages, here's a real-life example showing the particular merit of Scheme. I took on the task of creating a complex application (a web server supporting multiple hosts) and decided to write it primarily in Scheme (and some C). The first version was up and running in less than half a year.
Inevitably, months after the project was deployed changes were necessary. Despite the length of time since last seen, the code wasn't obscure to me, it was easy to understand and pick up where I'd left off before. Definitely different from prior experiences.
The crux is getting a good grasp on its core, macrology perhaps among the harder parts. But understood, Scheme allows enhanced productivity, as I've known it more so than other languages "under load" in parallel situations.