
A Little Clojure - ingve
http://blog.cleancoder.com/uncle-bob/2020/04/06/ALittleClojure.html
======
jmiskovic
Maybe this lisp syntax intro is a good place to ask veterans a related
question.

I find s-expressions quite beautiful and simplistic way to express both logic
and data as a tree. On the other hand, top-level evaluation rules are often
glossed over, and seem to mess up this elegance. I feel like there is a set of
braces missing at top level, for s-expression concept to be complete. I don't
really know enough about specific rules or reasoning why they need to be
introduced. My mental model of top-level execution is an implicit `(do ...)`
block. In rest of clojure code the `do` is a special form that is frowned upon
because it is used only when side-effects are necessary.

As it is, the 'module' concept is strictly tied to a file, which feels
unnecessary. If top-level was enclosed in braces and evaluated with same rules
as the rest of s-expressions, maybe we could move away from concept of files
and, for example, store our code in a graph database. This would allow for
IDEs that can collapse and expand code tree as needed.

Rich Hickey uses expression 'place oriented programming' as derogatory term
(PLOP) for relying on exact memory addresses as places for our data. It would
seem to me that same term would apply to our coding practices - we tie code
implementation to specific locations inside files on disk. This seems like
accidental complexity that introduces mental burden. If location of
implementation could be divorced from specific location inside specific source
file, we could concentrate on implementation that is always in context where
code is actually used.

Is there any decent discussion of such concepts, or some other language that
explores such direction? I'm lacking both terminology and in-depth knowledge
of code evaluation to express this in more clear way.

~~~
qwerty456127
I absolutely agree and think the same thing about Python - I dislike the
module=file relation because I often want to split a module into multiple
files and I also dream about storing code in a graph database often.

~~~
anentropic
There's nothing stopping you from splitting a module across multiple files in
Python

Yes, it will result in sub-modules

If you hate addressing code in the sub-modules via the sub-module path you can
import them in the __init__.py of the parent module

Personally I dislike languages which add another layer of (IMHO worthless)
complexity by decoupling the owning module of the code from the file path, so
you have now have to resolve that before you can understand it.

~~~
qwerty456127
Well, that actually needs to be transparent to be useful for the way I want to
use it. I can't even understand why would one need sub-modules so far. The
actual reason is to have different members (i.e. every method) or sets of
members of a same class to be implemented in separate files. I just hate to
have long code files and to have code above and below a function declaration.

Partial classes in C# are an example of how can that be implemented the way I
like it. The only problem with the C# way is it adds an additional indentation
level. I would prefer the module (or even the class) to be declared in the
beginning of the file without contributing to indentation.

------
ithrow
Clojure is the most productive(and beautiful) language in existence(personal
preference) as long as you don't have to leave its world.

I stop using it because the lack of Clojure libraries pushed me to use Java
libraries, and that was a life-sucking experience. Java is fine as language
but you cannot say the same about the APIs of many of its libraries. I also
started sensing that new open source libraries are not being created in Java
which worsens the story for Clojure.

~~~
diggan
The great thing about Clojure is that it's not tied to the JVM. JVM is just
one of the hosts.

So I mostly do frontend development at the time and I know Clojure since
before. Because of those two variables, I've chosen to use ClojureScript so
now I 99% of my professional time write only ClojureScript, with the remaining
time being 1% JS when needed. Otherwise the only time I see JS is when I have
to understand how a library works.

So I agree with you on the Java side, I'm not a Java developer and I want to
stay far away from it, but I love Clojure and I need to be close to it, any
other language feels inefficient and slows me down. But there are other hosts
you can use, if needed.

~~~
diggan
And since there is always someone who jumps in saying "Common Lisp is a true
lisp while Clojure is not", read
[https://en.wikipedia.org/wiki/No_true_Scotsman](https://en.wikipedia.org/wiki/No_true_Scotsman)
so we can have a real discussion about the difference ;)

~~~
kazinator
"No True Scotsman" is about moving the goalposts regarding to the quality or
suitability of something. We wouldn't reasonably say that a Dane isn't a True
Scotsman, right?

A piece of crap unsuitable for production use could be a Lisp. Lisp 1.5 is
Lisp; I wouldn't use it today. Lisp or not is not about quality, but
semantics. Clojure lacks or changes numerous semantics which define Lisp.
That's not statement about quality, just otherness.

Clojure doesn't call itself a Lisp; though the main website claims it is a
Lisp dialect. Dialects are defined by mutual intelligibility. An Osaka man
speaks a dialect which is understood in Tokyo. The mutual intelligibility
between Lisp dialects and Clojure does not extend very far beyond (+ 2 2).

------
john-shaffer
> (first 1 2 3) evaluates to 1, (second 1 2 3) evaluates to 2, and (last 1 2
> 3) evaluates to – you guessed it – 3.

This is wrong, unfortunately. He probably meant (first '(1 2 3)), etc.

~~~
dkersten
Since using lists are not so idiomatic, I suppose a better example would be
(first [1 2 3])

------
jp0d
Found this on the same blog --> [http://blog.cleancoder.com/uncle-
bob/2019/08/22/WhyClojure.h...](http://blog.cleancoder.com/uncle-
bob/2019/08/22/WhyClojure.html)

Thanks for this. :)

------
yakshaving_jgt
I don't see anything profound here, except perhaps that the language will
gladly accept the user's blatant type error and just explode at runtime. For
the most part this article is fetishising over basic syntax.

Surely the compelling parts of Clojure go somewhat deeper than basic syntax.
And if this is another tired discussion about legibility of syntax between
languages, I have to wonder why people are still so fascinated by this?

Between the following two representations of the same function…

    
    
      (defn f [x] (+ (* 3 x) 1))
    

…and…

    
    
      f x = 3 * x + 1
    

…I see very little difference in legibility. Sure, one is visually noisier
(and incidentally, the noisier, _less clean_ (!!!) notation is Robert C.
Martin's favourite) but if you can afford to navel-gaze this much on syntax
I'd question why you don't have anything more important to do. Of course I
recognise that I must also not have much better to do since I read the article
and I'm now commenting on it.

It's just _weird_ to me that one would fetishise syntax, and then describe a
language sporting a less visually-noisy syntax as "The Dark Path".

Edit: Apparently I need to state for the record that I spent a few years
writing Clojure professionally. I'm not unfamiliar — I just haven't drowned in
kool-aid.

~~~
malisper
I've programmed Lisp code for several years and personally I do find Lisp code
harder to read, especially when doing arithmetic.

The direct benefit of Lisp syntax is that everything is _consistent_.
Arithmetic operators have the same syntax as regular functions. Because all
Lisp code has a consistent structure, that makes it easy to do some really
neat things. For example, it isn't hard to write a program that takes Lisp
code as input and processes it in some way.

This is the reason why you see so many people write a toy Lisp interpreter.
It's really easy to write code to evaluate Lisp code because all Lisp code has
an identical structure.

As a Lisp programmer, this benefit emerges in the form of macros. Macros run
at compile time, take some Lisp code as input, and spit out new Lisp code as
output. The new lisp code is then substituted for the old one.You can think of
macros as a very small user-defined compiler. These let you build all sorts of
language constructs that you couldn't build in other programming languages.
For example, you can add pattern matching to a Lisp with macros. The macro
would take a list of patterns and corresponding expressions as input and spit
out some code that checks for the patterns and runs the corresponding
expressions if the pattern matches.

~~~
hope-striker
> These let you build all sorts of language constructs that you couldn't build
> in other programming languages.

Many languages (e.g. Rust[0]) let you write procedural macros, even if their
grammar is much more complex than that of a Lisp.

Is there some technical advantage to Lisp macros over macro processors in
other languages (ignoring string-based ones like the CPP), or do all the
benefits lie in the massively improved ergonomics of writing macros?

(Note that Rust also has simpler hygienic macros, but they're not expressive
enough for many things.)

[0]: [https://doc.rust-lang.org/reference/procedural-
macros.html](https://doc.rust-lang.org/reference/procedural-macros.html)

~~~
roenxi
You've pretty much covered it; lisps are better at macros than any language
with complicated syntax.

Most of the flow control in a lisp (for, while, if, etc, etc) can be
implemented with macros. It isn't often a program needs a new form of flow
control but when you need it it is there as an option and a lisp will do it
better than the competition. If Rust can do threading macros then it probably
has enough of the power that it isn't missing out. Still going to be a bit
cumbersome.

Lisps give you the option that flow control can be implemented in a library.
None of the old-school popular languages manage that.

------
hota_mazi
Uncle Bob discovers Lisp, 50 years after its creation.

Expect a follow up blog post telling us all software should be written in Lisp
and he has a Lisp book coming out soon.

~~~
fulafel
This guy has been writing about Clojure now and then for many years.

More generally.. if we start shaming people who discover Lisp after its
creation (1958) it's put in a rather unfair advantage!

------
0_gravitas
I'm certain most of us know who the author of this article, Robert "Uncle Bob"
Martin, is, but for those that don't:

Robert Martin is one of the original signers of the Agile Manifesto, which is
the outline upon which a great deal of modern software development is founded,
and helped set the tone for the Software Craftsmanship movement. Martin has a
large amount of talks (that are, admittedly, all quite similar to one another)
and blog posts (on the site linked) where he discusses his views as to where
the industry should go/should continue to go, with a heavy emphasis on
professionalism in programmers and programming teams.

~~~
yakshaving_jgt
Right. He touts "professionalism" while also suggesting that one "needs big
balls to write C++", because it is "a man's language".

------
_bxg1
Little a Clojure, as a treat

------
mwkaufma
"... as a treat!"

------
rb808
There are a hardcore group of developers that love functional languages.
Whenever I look it just looks pointlessly complicated.

Maybe its because I'm not smart enough? Given that 99% of software is not
written in these languages perhaps you have to have a special gene to figure
this stuff out. Or maybe its just people trying to be different or trying out
things on the fringe.

I'm not sure what the answer is or if I should try harder.

~~~
nickbauman
I find it the opposite. Lisp is much easier to write than, say Go. I think the
problem is if you're used to the complexity of writing a Spring Boot app
(Java) this simplicity of writing in Clojure will confuse you: you think it
can't be that simple when in fact it is.

I used to freak out when I'd find the library in Clojure I wanted to use but
it had no documentation. Eventually I just started looking at the
implementation and I'd see it's like the entire library is 35 lines of code!
Or like 102 lines of code! You don't need documentation for something that
small.

I've never seen this before in other languages. If you think it's too
complicated, you might just be overthinking it.

~~~
willberman
Could you share the 35 line library? I’m curious. I recently asked the Common
Lisp subreddit why so many of their libraries lack extensive documentation and
most agreed it is a wart on the language.

~~~
nickbauman
The one that this first happened with is now much bigger and well documented,
oh well.

(FWIW: it's shoreleave [https://github.com/shoreleave/shoreleave-
remote](https://github.com/shoreleave/shoreleave-remote), it allows for
exposing a server-side namespace as a client-side API in the browser).

------
benas
I have nothing against Clojure, but I agree with Donald Knuth who said:
"Programs are meant to be read by humans and only incidentally for computers
to execute." [1].

I could be wrong, but I don't find Clojure to be "simple" for humans to read
(or write). Here is an example from the blog post:

    
    
      So let’s write a simple one. Let’s write the factorial function.
      (defn fac [x] (if (= x 1) 1 (* x (fac (dec x)))))
    

Note the "simple one" here. I don't know for others, but this is not simple
for me as a human to read, understand and reason about. For instance:

    
    
      if (= x 1)
    

As a human, I read this like "if equals x one", which does not translate to my
natural language where I would say "if x equals one". So I need an additional
mental effort to do the translation. This is not the case in other languages
where "if x equals one" would be written like "if x = 1" or "if (x == 1)". If
the gap between the natural language and programming language is big, it is
difficult for a human to use that programming language. And for Clojure, this
gap is big IMO.

(I (wanted) (to learn ((some)) Clojure in the past) but [quickly] ([(realized
it was (not) for me)])) [2].

[1]:
[https://news.ycombinator.com/item?id=16430751](https://news.ycombinator.com/item?id=16430751)

[2]:
[https://twitter.com/b_e_n_a_s/status/1244417191556063234?s=2...](https://twitter.com/b_e_n_a_s/status/1244417191556063234?s=20)

~~~
sooheon
Formatting helps for presentation, just as it does for human text.

    
    
      (defn fac [x]
        (if (= x 1)
          1
          (* x (fac (dec x)))))
    
    

> (I (wanted) (to learn ((some)) Clojure in the past) but [quickly]
> ([(realized it was (not) for me)]))

This is missing semantics for morphology. Delimiters aren't strewn about
randomly, they precisely delineate the AST.

~~~
benas
Yes of course, that's incorrect and provocative in purpose. The point is not
about the syntax, but about expressiveness: A programming language should make
it easy for a _human_ to express (write) his intentions in code and for other
humans to interpret (read) those intensions in a _natural_ way. In other
words, the gap between the developer's natural language and his/her
programming language should be minimal (and this is regardless of the
developer's natural language, be it English or whatever).

~~~
Silhouette
_In other words, the gap between the developer 's natural language and his/her
programming language should be minimal_

I'm not sure that follows from the original claim at all.

Mathematics has plenty of problems in when it comes to obscure terminology and
regrettable notations, yet still vast numbers of people prefer the conciseness
and precision of mathematics to using natural language when they want to
discuss concepts in science, engineering, programming, etc.

At some point, if you're going to work in a technical field, you're going to
need terminology and notation to match. Newbies to the field need to learn
those before they can understand what is being said "naturally". The
alternative is to attempt to dumb everything down to the point where newbies
can understand it straight away but, assuming it is even possible, this risks
losing a lot of effectiveness in communications between everyone who does have
more experience.

~~~
benas
Writing code is different from writing mathematical equations. Developers
(humans) prefer meaningful variable names, method names, expressions, etc.
Comparing this to maths where conciseness is key is not the best analogy IMO.
And it is not about experience (btw, I have no problem being one of these
newbies who "need to learn those before they can understand what is being said
"naturally""), it is really about expressiveness to reduce the mental effort
to match things (what I have in mind and what I see in code). That's why there
are many attempts [1] to create programming languages that are as close as
possible to people's natural languages.

[1]: [https://en.wikipedia.org/wiki/Non-English-
based_programming_...](https://en.wikipedia.org/wiki/Non-English-
based_programming_languages)

~~~
Silhouette
_Developers (humans) prefer meaningful variable names, method names,
expressions, etc._

Well, isn't that part of the premise we're debating?

Mathematical papers and books tend to have the advantages of dealing with only
a handful of concepts at any given time, and of presenting their mathematical
content in relatively small doses, both of which allow concise notation to
remain both unambiguous and accessible enough to be useful. Anything other
than the smallest programs probably do not enjoy the same advantages, so it
makes sense that programmers tend to use longer names for entities that are
relevant over a larger area. However, this argument still allows for short
names to be used in programs as long as the scope is also small, and it says
nothing at all about the relevance of natural language for representing
programming language constructs.

We have some experience with programming languages that do try to read very
much as natural human language. COBOL is probably the most famous example, and
in that language even basic mathematical concepts like comparisons can be
written out in words. We don't write much COBOL today, and it's hard to
believe that the verbosity isn't a contributing factor in that.

~~~
benas
No, you are deviating from the main point: natural expressiveness. So let me
back up: If you think "if (= x 1)" is natural to humans, then try to ask
someone in the street "is equals this that?" and let me know about their
reaction. My point is that the natural way of asking such questions is:

    
    
      * "Is this equals to that?" and not "is equals this that?"
      * "Is this bigger than that?" and not "is bigger this that?"
    

And this is regardless of the language (be it English or whatever, see
[https://news.ycombinator.com/item?id=22811168](https://news.ycombinator.com/item?id=22811168)).
I'm not going to debate this to death, so feel free to disagree. Again, I have
nothing against Clojure, I'm just trying to argue in a constructive way.

