"imperative" does not seem like a good/valuable characterization. Yes, the "do" form is imperative. That's why you're not supposed to use it much, perhaps only for the top-level structure of your program, the part that acts as an interpreter to connect the pure program to the outside world. <i>When you express business logic in a language like clojure</i>, that expression of the business logic is not usually "a sequence of commands executed in order". It usually looks more like "an expression tree and rules for how nodes are evaluated".<p>The downside of a simple, transparent language like lisp is that it exposes you to the dangerous parts of the underlying. An opaque abstraction (e.g. expressing database operations as a tree of operations some of which define transaction boundaries, rather than as a series of SQL commands some of which open or close transactions) is vital for transforming dangerous things into safe things. Ultimately a program looks like an expression of business-level logic and then an opaque layer that pretends the computer is actually a machine that understands your business. Lisp forces you to provide more of that opacity yourself, whereas a language that already has a vocabulary for drawing distinctions between different kinds of thing provides you some of the scaffolding you need (the tradeoff being of course that it will be less specialized to your particular circumstances).
Just because Clojure has the DO form (or that Common Lisp has the PROG form) doesn't mean that the language <i>is</i> imperative. It means that it <i>allows</i> imperative programming.<p>This is like saying that a language with casts doesn't have a type system. No, it has a type system, it just also has an escape hatch that lets you break out from the type system when you need to. Lisps' functional-ness is generally the same sort of thing: They are designed primarily around function-oriented programming, but provide straightforward escape hatches into imperative programming. Common Lisp tends more towards being multi-paradigm than Clojure (i.e. provides more imperative accommodations), but both have strict evaluation, which the author seems to equate with imperative-ness.<p>The author spends more time talking about a small core and non-leaky abstractions than about imperative-ness. On these points, I totally agree and think it's a well-written article. I don't exactly see the connection with being imperative, and I think it's a shame that the title will draw attention away from those points. The thing that I really like about working in Clojure is how the abstractions are built with care: I feel like whenever I just use the base building blocks, they fit together seamlessly and edge cases usually don't come up.
From what I've read, the exact definitions of imperative and declarative vary a lot. The most useful rule of thumb I've come across is to consider imperative to be concerned with HOW something is to be done, while declarative concerns primarily WHAT is supposed to be done.<p>SQL is usually classified as declarative in that you're not telling the database how to retrieve the top ten entries from a table - you're merely informing it that you are interested in those entries.<p>It struck me at some point that this definition must be relative to the level of abstraction you're operating at. For example, when using (go …) blocks, I'm declaring that I want the code contained within the block to be processed asynchronously, but I'm not describing how that is to be done. Perhaps a callback might be described as being "more imperative" since it contains more implementation details?<p>So, am I correct in thinking that this discussion would hinge on what you consider to be "concrete" and not? That something executes in sequence is hardly enough to decide whether it is to be considered declarative or imperative in nature.
<i>You would only want to execute an expression and throw away its value for its side effects.</i><p>Useful for IO as there's normally nothing I want to pass the value of a println expression to, evaluating already prints it to stdout. Also useful for mutation, but doing this in Clojure feels wrong since the immutable data structures are among the language's greatest strengths.
"Imperative" isn't really a binary feature of programming languages, the imperative-declarative axes is more a continuous axes of variation describing code (which can be applied to languages, as well, as a general characterization of code written in the language.)<p>And, while its certainly possible to write very imperative code in clojure (or even Haskell!), idiomatic clojure is more declarative and less imperative than most popular languages, so, I think, on balance, "is imperative" is not a useful description.<p>That being said, in most "declarative" languages, there still remains the risk of being bitten by issues related to order of operations and structure of the code that aren't apparent if you view the code as <i>purely</i> declarative statements of intent rather than as to some degree imperative instructions. And if you call anything that presents that issue as "imperative", virtually <i>all</i> programming languages are "imperative".
I just started learning Clojure, so I don't really understand this article very well. Is Clojure significantly different from other LISPs (e.g. Racket)?
Which language is not imperative then? The only program writtten in non-imperative language I can think of would return random values (of random type, also not known to mankind, including total destruction and creation of life) and crashed avery second function call.
He explain his intention was another thing, and this post make it more clear, I think:<p><a href="http://www.lispcast.com/two-kinds-of-bootstrapping" rel="nofollow">http://www.lispcast.com/two-kinds-of-bootstrapping</a>
He talks about how lisps are bootstrapped on a small core, and that is nice. Reminded me that this is the approach that Perl 6 is trying to take (NQP is the core) although on a larger and more complicated language