
A History of Clojure [pdf] - puredanger
https://clojure.org/about/history
======
Naomarik
Prior to Clojure I feel that I didn't really know how to do things well.

In the context of the domain I have the most experience with, web
applications, I'd summarize the bulk of programming as defining data, data
transformations and shoving data through APIs. Once you get the hang of it,
Clojure makes it trivial to transform datastructures from A to B. This has
enormously expanded the kinds of problems I can solve.

When Rich says "It was impossible to avoid the sinking feeling that I had been
“doing it wrong” by using C++/Java/C# my whole career."

I feel somehow that this is the case for the majority of people but they don't
realize it yet because their experience is the most popular trendy language or
framework. I've seen many examples of libraries in different languages having
enormous amounts of commits and hundreds issues for problems that are trivial
to solve in Clojure.

I was in the same boat, constantly grabbing for frameworks and if one wasn't
available that made my task simple, would struggle trying to bend the
frameworks or language I was using to come up with a solution.

I'm not a language geek and I don't write code outside my work for fun. I want
to spend the least amount of time possible in front of the computer and sleep
knowing my web applications won't topple over. Clojure has fit me so well that
I don't think I would have accomplished what I have in other languages.

~~~
natdempk
Could you elaborate on a problem that illustrates this property of Clojure?
This sounds awesome, but I have a hard time understanding what you're getting
at without knowledge of Clojure.

~~~
drcode
Three examples of this:

1\. core.async: So the guys who built golang did it because they had this cool
idea for creating coroutines using channels. However, since it required very
low-level functionality to be part of the core of the programming language,
they thought they'd have to design a brand new language to implement their
idea. However, shortly after golang was released, Rich and some other clojure
folks implemented the same feature in clojure as a totally ordinary external
library, proving that the core of clojure was general enough to support this.
And it wasn't just a gimmick: I use core.async every day and think it is
better than golang's implementation.

2\. The Expression Problem: One of the core challenges in language design is
designing it so that (simplifying a bit) you can transparently add support for
new function methods to objects designed by a third party. Clojure makes this
easy [https://www.infoq.com/presentations/Clojure-Expression-
Probl...](https://www.infoq.com/presentations/Clojure-Expression-Problem/)

3\. Lots of languages have attempted to allow you to write a single library
that you can use both on the client and the server, having your code
transpiled to different languages in each case. However, this type of feature
is rarely used in production, because there are usually lots of headaches
involved, with many limitations. However, for clojure developers it is
perfectly normal (and usually expected) that all code is written in cljc files
& so that it can be used on both the client (transpiled to javascript) and the
server (transpiled to java). It is easy to do this, even for cooperatively
multithreaded code.

~~~
hy3rm0n10us
2\. requires static typing in my personal opinion

cf. [http://lambda-the-ultimate.org/node/4136#comment-62959](http://lambda-
the-ultimate.org/node/4136#comment-62959)

~~~
mumblemumble
tl;dr on the above: The Expression Problem was originally expressly formulated
with maintaining a Haskellian level of static type checking as one of its core
requirements.

Saying you've solved it, when your solution involves on dynamic typing, or
even casts in an otherwise static language, is arguably akin to kicking the
ball across the center field line and then claiming you've scored a goal.

(See:
[http://homepages.inf.ed.ac.uk/wadler/papers/expression/expre...](http://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt))

~~~
heretoo
Actually, clojure compiles down to java classes, which are statically typed.
Existing java types can be extended with clojure protocols. The link below
talks about this, specifically about the expression problem.

See [https://www.ibm.com/developerworks/library/j-clojure-
protoco...](https://www.ibm.com/developerworks/library/j-clojure-
protocols/index.html)

However, I learnt something. I didn't know that the definition of the
expression problem required static typing. I prefer to think of it as adding
static types to multiple dispatch.

~~~
mumblemumble
You missed a detail: _or even casts in an otherwise static language_.

Clojure does compile down to Java classes, but Java is only a partially
statically typed language. It also permits run-time casting, which, in a
language that even tries to be strongly typed, means run-time (to wit:
dynamic) type checking. And Clojure relies heavily on that.

That's why I invoked Haskell. It's an example of a language that is _truly_
statically typed, in that it doesn't (generally) permit any run-time type
conversions. ALL type checks must be done statically.

~~~
heretoo
Then, the conclusion can be that dynamic languages don't suffer from the
expression problem.

~~~
mumblemumble
Pretty much. Not entirely unlike how one can't implement the Y combinator in a
statically typed language, but it's trivial to do so in a dynamic language.

------
_bxg1
The fascinating thing to me about Clojure is that it's so vocally a
"practical" language, and yet is a) a Lisp, and b) purely functional[1].
Usually those two things are associated with language enthusiasts, and not
"""pragmatic""" development. In the end it works, clearly, it's just very
interesting to see that juxtaposition.

I think it says something interesting about the practical value of higher-brow
programming concepts, but also about how important the
packaging/marketing/ecosystem is to conveying that value and making it
accessible to the masses.

[1] I know it's technically not 100% functional, but all of its messaging
highlights that philosophy as a focal point and advantage.

~~~
amelius
> The fascinating thing to me about Clojure is that it's so vocally a
> "practical" language

I tried Clojure, but the startup times were too large to the point where it
became impractical. Especially for small scripts.

~~~
didibus
If you read the history, you'll see that small scripts was never a use case
targeted by Rich Hickey. It was focused on information systems programming,
where a few seconds of startup time is a blip on the full running time of the
application.

That said, slow startup times are only true of Clojure JVM. ClojureScript and
Clojure babashka, for example, both start fast enough for small scripts.

Also, seems the JVM is slowly improving in startup time department. I was
surprised to see that a hello world is now down to 800ms start time on my 2011
laptop with Java 14. It was 3s before with Java 8 on the same laptop.

For comparison, ClojureScript hello world was 550ms, and babashka hello world
was 36ms. Python hello world was 68ms and Ruby was 111ms.

~~~
omaranto
> Also, seems the JVM is slowly improving in startup time department.

It's not the JVM that makes Clojure JVM slow to start up, try comparing hello
world in Java vs hello world in Clojure.

~~~
didibus
It's true that Java hello world will be faster than Clojure JVM hello world.
That said, a big Java application with lots of classes to load, and lots of
static initializers (which would approach the same number as what Clojure
requires to be loaded and initialized) would take as much time as it does for
Clojure.

So when people say that part of the slow startup is Clojure's fault, they mean
more that it is implemented in a way that the JVM isn't very fast at starting.
But if you look at Clojure implemented on other runtimes, like ClojureScript,
the startup times are much faster, because the NodeJS runtime is much faster
to start and initialize everything than the JVM is.

In effect, if the JVM improves startup times, so will Clojure JVM's startup
times be improved. That's why I see this drastic difference between a Clojure
hello world on Java 8 vs Java 14.

------
brabel
Great story, really enjoyed reading. Rick Hickey is a great speaker (if you
haven't watched his talks on youtube, do it! They are totally worth it), and
certainly a great programmer, which is why I respect his opinions on dynamic
typing, even if I stubbornly disagree (one day I might still dive into
Clojure, but I am diving into the arguably opposite end of languages right
now: Rust!!). I have even more respect for him now knowing that he actually
worked on Clojure for years without any income!! This is a work of passion,
and I admire him for that, and for being able to turn that passion into a
company big enough to pay his bills and that of several of Clojure's early
adopters.

~~~
mapgrep
>I have even more respect for him now knowing that he actually worked on
Clojure for years without any income!!

Hickey mentioned in one of his talks that he actually burned through
retirement savings (at least some?) while taking these years to do Clojure. I
got the impression he had been thinking about it for a while prior and that it
was in the neighborhood of two years. (The context was, he was thanking his
wife for helping to make Clojure possible, in part by indulging in many
converstions about very minute details of how Clojure would work.)

(I have no idea if this is covered in the paper as it's 46 pages, I've
bookmarked it but not yet read it.)

~~~
brabel
In those 46 pages, he goes into details regarding how the idea came up to him,
why he took a sabbatical of 2 years (which ended up lasting to this day, he
says at the end :D ), what he did during those 2 years (not only Clojure) and
how he basically has no retirement savings left because of that.

------
tom_b
I remember being at the first Clojure/conj - I had just spent some time
learning a bit of Common Lisp and stumbled onto the conference announcement
somehow.

This was very fortunate for me - after attending the conj, I was able to use
Clojure at work to sneak in some FP on the readily-available JVM platforms. I
later used it to do some internal REST-API work. The code for that project has
run for _years_ without modification or error.

For whatever reason, I also discovered that thinking functionally with Clojure
worked so much better and naturally for me than object-oriented design
methods. While I have drifted away from Clojure over the last couple of years,
I find that my problem solving mind is much better in other languages because
of the time spent thinking functionally with Clojure.

~~~
adamkl
_" The code for that project has run for years without modification or
error."_

To follow up on this point, if you ever need ammunition to sell the use of
Clojure inside an enterprise level organization, just show your Chief
Architect the graphs of code stability over time for Clojure (pg. 71:26) and
ClojureScript (pg. 71:30).

After working with JavaScript (not trying to bash) for the last few years, the
idea of stability has become top of mind for me.

~~~
O_H_E
Wow, I didn't expect such differences compared to Scala. These graphs need a
study on their own.

~~~
puredanger
[https://erikbern.com/2016/12/05/the-half-life-of-
code.html](https://erikbern.com/2016/12/05/the-half-life-of-code.html)

~~~
adamkl
[https://www.groundedsage.dev/posts/the-clojure-
mindshare/#he...](https://www.groundedsage.dev/posts/the-clojure-
mindshare/#heading-stability)

------
bangonkeyboard
I was at a talk by Guy Steele where he mentioned in passing that Clojure was a
Lisp which had done everything right. This was all the more impressive to him
because Rich Hickey had until then been a relative outsider to the Lisp/Scheme
community.

~~~
globular-toast
I just wish it didn't target the JVM. I think if it had a native runtime that
loaded quickly like Python it would be more popular. I love Clojure and really
wish I could use it, but I just don't do the kind of things that can justify
running a JVM.

~~~
keymone
JVM is not to blame here, it's Clojure that takes a while to load and
initialize. Java actually crushes Python in every aspect in terms of
performance (which is to be expected of statically typed language).

~~~
lvh
GP specifically mentioned startup time. It's true that most of the startup
time for Clojure projects is a Clojure-specific interplay of things the JVM
does (but also not language-intrinsic: ClojureScript on V8 does not share that
problem, for example), but default flags CPython still beats default flags
OpenJDK for "start and do nothing".

~~~
keymone
> default flags CPython still beats default flags OpenJDK for "start and do
> nothing"

i stand corrected :)

------
adamkl
A great quote from the introduction, on why Rich took a sabbatical to work on
Clojure:

 _...to give myself the opportunity to work on whatever I found interesting,
without regard to outcome, commercial viability or the opinions of others. One
might say these are prerequisites for working on Lisps or functional
languages._

~~~
microcolonel
The results are also astounding, because what he came back with produced
extreme commercial viability, and is excellent in the opinions of others.

Having used Clojure professionally for a couple years now, I feel so blessed.
It is really well cut out for a whole host of problems that are common but
extremely labour-intensive in conventional languages.

Maybe one of these days I'll get time for my own sabbatical, and solve the two
major tasks I see with Clojure: taking the performance from good to excellent;
and hosting it in a robust systems language suitable for implementing well-
trodden functions.

~~~
jonahbenton
Yeah, share both common concerns, centering around the JVM (which I love, and
have used and studied since it launched, but it is baggage).

There have been a number of attempts to build Clojure on top of Go (I worked
on one), and another on top of Rust. Both lack the dynamic runtime ergonomics
that Clojure leverages. Clojure is also seeing significant performance
benefits, both runtime and startup, from the Graalvm, but that also will have
limitations.

I am wondering about D, which should be sufficiently low level from a systems
perspective but may also have sufficient dynamic capabilities.

~~~
microcolonel
I think the problem with Go is that it is invested in some oddities that are
of a similar scale to Java oddities. For example, from my ignorant
perspective, Go's multiple return pattern for error handling seems to have
turned out in the long run to be a much bigger mess than Rust's Result.

AFAIK Rust ditched the optional GC long ago, but I think a lot of the
infrastructure that has enabled async/await, in the way of hooking in a
“runtime” through attributes and macros, could help with building a GC into a
rust host. I think this could be a special strength if you combined the
futures infrastructure with the allocation logic, maybe with a local
spill/scratch pseudo-heap for allocations that don't escape.

Think ztellman's aleph and manifold interfaces, but based on tokio, with some
of the allocation magic (or deallocation magic, depending on how you slice it)
of BEAM.

I think I've been a bit let down by some “Clojure-inspired” languages which do
not have HAMT or CHAMP datastructures, or do not have good implementations of
them.

The JVM's profusion of high-quality garbage collectors is another thing that
is hard to compete with; though I think there are massive opportunities with a
collector similar to Shenandoah 2.0, if the allocator can be aware of the
properties of Clojure.

Furthermore, a purpose-built runtime would be an amazing way to explore
transparent non-volatile memory. I think there is staggering value in
transparent access to datastructures that are significantly larger than
memory, especially if that access is inside a future/task run by a NVM-aware
executor, and can wait safely. Think MapDB, but persistent, immutable,
indistinguishable from the standard Clojure datastructures, and integrated
with the garbage collector.

Of course, as I've not written anything significant in Rust, I will shut up
about it beyond this, because there's nothing more obnoxious than people
extolling the virtues of something they've never accomplished anything
significant with.

~~~
jonahbenton
Heh, I actually like the "comma-ok" pattern and use it in Clojure.

IMO one of the areas of abstraction leak in Clojure is around error handling.
Most of the time the options- out of band and out of code path, like
Exceptions, and in band, like null- don't sit well with me. I usually want in-
band, explicit, with the capacity for some sugar so if necessary the error
cases can be organized in one place. Comma-ok does this for me without any
magic, and I would like to see it as a lowercase-p protocol integrated into
things like the threading macros (there has been some work in this area...)

But high level, comma-ok is just data, not a type- another area of abstraction
leak.

I hear the interest in arriving at a more efficient GC but don't have much
current background in that area. I did a lot of GC work at the configuration
level with the JVM, and read a bunch of the source a decade or more ago, but
recognize that's not my area. I similarly spent a bunch of time in the linux
kernel world 15 years ago, and still check in on the mailing list from time to
time, but that's a different life.

Agree with non-volatile mem opportunity, though note that was the intent with
virtual memory architectures and then CPUs went and ruined it with the cache
hierarchy. From a performance perspective if your code is hot, cache-aware
will noticeably outperform non-cache aware. Figuring out ways to make this
automatically efficient at runtime in the context of also supporting GC would
be a fascinating PhD project.

Appreciate the engagement, cheers.

------
rafaelferreira
I've been working with Clojure for a few years now, and the thing I love most
about the language is how it nudges developers to write straightforward code.
It's maybe closer to a well-structured procedural style than to highly
indirect OO or to deeply polymorphic category-theory-inspired typed functional
programming. The emphasis on mostly-first-order pure functions composed of
other functions, receiving and returning immutable values, makes it easy to
untangle even the worst balls of mud, while the well designed set of data-
structures (few) and functions operating on them (many) allow for easy and
terse expression of everyday data manipulation chores.

If we keep the majority of the code pure and straightforward, we can deal with
state and I/O with other constructs, like atoms and records, only where we
need to (doing this systematically tends to lead me to some variation of the
functional-core/imperative-shell pattern). STM, multimethods, macros and
whatnot are cool and have their uses, but after a while I think the really
cool thing is how little do we need to resort to fancy stuff and how much is
accomplished with just functions and data.

~~~
leethomas
> functional-core/imperative-shell

Lol I’ve been learning Clojure for fun these last few days and I had to read
this twice because the first time I thought I was looking at a function from a
module.

> we can deal with state and I/O with other constructs, like atoms and records

Can you elaborate on what you mean here or link to specific articles? I’m
talking about the representing I/O side effects as records part.

~~~
roguas
There is a component framework that builds dependency tree for stateful
modules and does implicit injection of params. It is a beautified
pattern(usually you can do initializations in higher levels, but you have to
resolve dependiences yourself and for the whole tree) for dealing with things
that require state while keeping explicit references(so that you understand
where it came from and can inspect(visually) its lifecycle).

------
simongray
> When I first was learning Common Lisp I was appalled at the tolerance on
> Usenet comp.lang.lisp of arrogance, hostility, intimidation and other anti-
> social behavior of the presumed ‘smartest guys in the room’. I was
> determined (a) that the Clojure community would not be hosted there and (b)
> that kind of behavior would not be tolerated.

Thank you, Rich Hickey!

The persistent data structures and functional core library are great, but many
would not bother with Clojure if they had to deal with the toxicity that is
present in the Common Lisp community.

~~~
bjoli
Comp.lang.lisp was awful, and the trend somewhat continues even though it has
gotten better. Looking through newb threads on various lisp forums there are a
few people that always seem to try their best to be mean or funny on someone
else's expense.

It is not that hard: if someone writes awful code, point them in the right
direction. Don't claim they have malfunctioning brains.

I stopped writing CL a few years ago even though I enjoyed it. For my personal
stuff scheme is even more fun, and the communities are a lot more pleasant.

------
elamje
I was super excited to see this paper released. I've spent time with Python,
Java, C#, Javascript and limited time on C and Rust. Clojure was the largest
paradigm shifter by a large margin.

Having done concurrent programming in Java, and even implemented some
concurrency primitives like semaphores, Clojure was incredible to use. For
those that don't know, Clojure uses immutable data structures that mitigate
concurrency issues. If you are curious how that's even practical, I highly
recommend the paper and also reading about Persistent Data Structures. They
reuse shared data, similar to how Git only tracks the delta's between commits,
rather than multiple, full copies of the file.

On top of that, you up reducing lines of code by 60-70% of traditional Java or
C#.

~~~
adambyrtek
> They reuse shared data, similar to how Git only tracks the delta's between
> commits, rather than multiple, full copies of the file.

I learned about immutable data structures at Rich's conference talk years ago,
and the whole concept blew my mind as well. However, what you said above is
not strictly correct. The idea is not to store deltas (which is what
Subversion does), but immutable copies of objects (in case of Git identified
by their SHA-1) that can be used to build multiple versions of a hierarchical
data structure (e.g. a list, tree or hash map). Git commit is basically a tree
of other objects with some metadata. The problem with deltas is that they need
to be iteratively applied to some base snapshot which requires computation
(and probably a cache as well), while immutable objects are easily accessible
in constant time.

~~~
elamje
Agree. Probably should’ve used a more solid example, but was just trying to
convey the essence I suppose.

~~~
adambyrtek
No worries, I fully agree with the rest and just wanted to clarify things for
others, not nitpick.

------
jwr
Thanks to Clojure (and ClojureScript), I was able to build my self-funded SaaS
business. There is no way I would have been able to tackle the complexity
without Clojure.

I also love the mature approach and mature community. It is, quite simply, a
different world from most other software places, and one I enjoy a lot, as I'm
mostly focused on building and shipping a large and complex codebase with an
extremely small team.

~~~
GiorgioG
Can you elaborate on how Clojure helped you tackle the complexity? I've
considered learning Clojure (I have the Brave Clojure book sitting not far
from me) but I have concerns about the learning curve (I'm a fullstack dev by
day (C#/Angular) slowing me down in my own attempt to build a SaaS.

~~~
jwr
Well, off the top of my head:

* a single language for both client-side (browser) code and server-side code

* a single data representation (maps with namespace-qualified keys), so no conversions necessary

* spec which helps validate data in multiple places (such as :pre/:post conditions)

* core.async which lets me write asynchronous code both in the JVM and in the browser, same primitives

* a library of excellent sequence manipulation functions

* transducers, which let me build composable data pipelines

* the Rum library which lets me use React as a rendering engine, basically a function of my data

* most of my domain code is shared between the browser and the server

There is more, but these were what I could come up with immediately.

I mostly spend time thinking and working on the problem domain, not writing
boilerplate (there is none in Clojure, really).

~~~
d_t_w
I think we might be clones. My self-funded business
([https://operatr.io](https://operatr.io)) is built in Clj/Cljs.

From the product, to the static website, marketing emails, even the licensing
runs Cljs on Node in AWS Lambda.

I would have listed those same bullet points off the top of my head.

------
roryrjb
I see nothing but praise for Clojure and for good reason. I experimented with
it a bit a few years ago and it seemed to be a more practical and useful
version of Lisp, although I say that as someone who wasn't that experienced in
Lisp more generally, with only some small experiments in Scheme. Something
just as significant was that the ecosystem seemed to be quite sane and I got
on really well with Leiningen for example, if you were considering diving in
then give it a go.

I personally won't consider it now but not because of the language or the
ecosystem but because of the runtime(s). For me the layers of abstraction are
too much complexity to not be justified.

~~~
puredanger
It seems that rejecting all of the most popular runtimes in the world (JVM,
JS, CLR) is an odd thing to have a grudge about.

(Also notable, babashka, a Clojure alternative to bash.)

------
LandR
I love clojure the language but hate the tooling.

Also a lack of documentation was always a problem, especially around clojure
script.

I also don't like smug community. When you say about the lack of documentation
and get told that's a good thing, clojure is meant to be hard to learn, it's
not for everyone and maybe you just aren't smart enough...

Hmmm. That attitude might put people off.

~~~
james-mcelwain
What tooling has given you problems? I think that some tooling assumes
familiarity with the Java ecosystem (which is a problem for many things in
Clojure land), but otherwise it seems pretty solid to me.

~~~
Royalaid
I have posted about this before but Clojure does have tooling problems
specifically ergonomics.

Look at create-react-app. Two commands and a ton of editor integration across
intellij, vscode, vim, etc gives you incredible access to a rich ecosystem and
plugs together really nicely with sensible defaults.

Clojure has some answers in this space but everything feels bolted on and not
nearly as polished. A big part of the problem is the size of the community,
there just isn't enough hands to build out the infrastructure that other langs
enjoy.

I still love Clojure and will continue to use it but in order to do so I have
to understand that some simpler things will just be more work.

~~~
dragandj
That might be because you've left out CIDER, which is

1) the most popular Clojure programming environment

2) solidly documented

3) built on top of Emacs, which is in itself very well documented (Just the
reference manual of the vanilla Emacs is 500 nicely written, if dry, pages)

4) _very_ featureful.

I guess the biggest problem is that most people are not familiar with Emacs,
and not willing to read _any_ documentation and guides.

~~~
jlarocco
I've never understood why so many people are reluctant to learn Emacs (or
Vim), but then don't see any problem with learning a new language specific IDE
every few years.

~~~
dTal
Probably because those language-specific IDEs all follow standard user
interface conventions.

------
mark_l_watson
I used Clojure a lot back in the beginning (contributed a little money, used
Clojure fairly intensely on two long term consulting projects). Before that I
used Rich's Common Lisp to Java bridge project. I think his impact goes far
beyond just Clojure users, having helped push immutable by default, etc. as
standard good practices.

I moved away from Clojure because I wanted to move away from the JVM. I did a
fun project, a nutrition/cooking web app [1] about 12 years ago in Clojure,
but I am slowly porting that from Clojure to Common Lisp for another example
program for my book [2]. Perhaps not as well known, but Clojure joins other
less commonly used languages like Haskell as languages with fairly good
support for deep learning. I feel like any language that does not have a good
deep learning story will be limited. Also interesting that Swift has such good
access to Apple's deep learning libraries and also a version of TensorFlow. I
encourage Clojure developers who work on deep learning support!

[1] [http://cookingspace.com](http://cookingspace.com) [2]
[https://leanpub.com/lovinglisp](https://leanpub.com/lovinglisp)

~~~
synthc
You can subscribe to Dragan Djuric's deep learning book [1]. He is using the
subscriptions to fund work on Deep Diamond [2], a fast Deep Learning framework
with GPU support for Clojure.

[1] [https://aiprobook.com/deep-learning-for-
programmers/](https://aiprobook.com/deep-learning-for-programmers/) [2]
[https://github.com/uncomplicate/deep-
diamond](https://github.com/uncomplicate/deep-diamond)

------
lbj
I've been here for the entire journey, but no one can summarize it quite like
Rich. And I bet he could write twice that just on nurturing a community - He
spend hours and hours on IRC in the early days, coaching, teaching, correcting
and even admonishing bad behavior. He's truly done something remarkable in
both building this powerful language that I use daily, and a very helpful,
friendly and intelligent community around it.

------
christophilus
Clojure is hands down my favorite language that I've used so far. Rich, if you
read these comments, thanks for all you do!

------
lukashrb
A great read! What I really appreciate, beside all the technical stuff, is the
effort to create a positive and helpful community around Clojure.

From the paper: "When I first was learning Common Lisp I was appalled at the
tolerance on Usenet comp.lang.lispof arrogance, hostility, intimidation and
other anti-social behavior of the presumed ‘smartest guys in the room’. I was
determined (a) that the Clojure community would not be hosted there and (b)
that kind of behavior would not be tolerated. Early on, on IRC and the mailing
list, I established and required a tone of supportiveness, positivity and
respect."

------
abraxas
I fell in love with Clojure and fell out of it. It is a great language. Lisps
have this inherent elegance to them especially in data transformation
pipelines.

That said I found its performance still a bit on the wanting side particularly
if you avoid type hints. For many tasks the performance is probably acceptable
but the backend work I tend to do makes the abstract style get in the way of
trying to figure out performance issues.

Also I'm coming around to the imperative style more and more. Sometimes a for
loop is all that's needed and makes for a more understandable code than all
those hipster maps and folds.

~~~
ashtonkem
I also found that Clojure is full of weird edge behavior. Sets are unsafe, and
might change the type on you. Seq leaks like a sieve, so there are all kinds
of places where you have to map seq, and type hinting is the _worst_. The
moment you type hint a Protocol, all kinds of weird shit starts to happen,
including the need to import the type hinted classes in the consumer (except
Java.util.*), even if you don’t reference it. Oh, and if you type hint
protocols wrong, it doesn’t error, but your performance remains bad.

At least it did in 2017. I haven’t used it since then.

~~~
puredanger
I don't know what "sets" refers to here - idiomatic Clojure does no such thing
(there are some facilities with the word "set" in them but they are all rarely
used). seq is not leaky at all imo, it's a model that choose to use
([https://clojure.org/guides/faq#seqs_vs_colls](https://clojure.org/guides/faq#seqs_vs_colls)).
Or you can choose not to use it now with transducers and use any of the seq
functions and collect into a specific collection type. I don't know what
you're talking about with protocols, typically you don't need to type hint
them, and I think there may have been an issue with unqualified imports on
referred functions but that was fixed several releases ago.

~~~
ashtonkem
Set as in the collection. Sets are idiomatic, they even have syntax sugar for
their construction: #{}.

Seq is extremely leaky, as whether or not a built in function takes a seq or a
specific collection is undocumented and arbitrary. Hashmaps for example do not
accept seqs when using “into”, it accepts vectors. So my code was littered
with (into {} (map vec <thing>)). That’s a leaky abstraction.

You need to hint protocols if you want to go fast.

------
bpyne
Section 2.4 of the paper gave me a chuckle. Like Rich, I've yet to write a
program that didn't involve some kind of database. Organizations care about
data not programs. Writing programs just gives them a way of applying
organization-specific rules, in the way of transformations, to the data.

------
imdhmd
As an aside - Is Rich Hickey still not notable enough to have a wikipedia
entry? Even the person who has shepherded on this paper has a wiki page.

~~~
ImprobableTruth
What is notable about Hickey besides being the creator of Clojure? Not to say
that this alone doesn't make him notable, but I also don't really see the gain
in an entry that is just a glorified redirect.

~~~
puredanger
He also created the Datomic database
[https://www.datomic.com/](https://www.datomic.com/)

~~~
dragandj
All right... all right... but apart from better sanitation and medicine and
education and irrigation and public health and roads and a freshwater system
and baths and public order... what have the Romans done for us?

~~~
foobar_
brought good syntax ?

~~~
macmac
And a pretty but impractical number system.

------
lymeeducator
Thanks to Rich for designing and thanks to Alex & Rich (and others) for
maintaining. It is my favorite language thus far out of (Java, Ruby, Python,
Bash, Awk, Erlang, Swift, Tcl and Objective-C).

------
redisman
Has anyone used Clojure much? I love Rich's talks so I've been very interested
in it but there are so many great languages to learn these days.

~~~
_bxg1
I did one personal project in it just to get my feet wet. Unfortunately the
tooling was not great at the time so it soured my impression a bit (I'm told
it's gotten better since then).

But also, I just have a really hard time giving up static types these days.
Even for small projects, I always feel anxious about code that doesn't have
annotations on function boundaries. It may have more to do with personal
sensibilities than actual need, but regardless, it makes things unpleasant for
me.

~~~
hannofcart
Same here: having gone from C++ to JS+Python and back to Golang/Rust, I just
can't imagine life without types.

However, of all the not-static-typed language ecosystems I see, Clojurists
seem to miss types the least. I have dabbled with the language and I know
about `spec` but I don't quite seem to grasp why even shops using Clojure
without spec don't seem to miss types much either.

Perhaps people more experienced with Clojure can shed light on this?

~~~
lorddoig
It depends what you want to use types for, really. If your motivation for
using types is provable correctness and you can grok Haskell (or better yet,
Idris), then you should do that. If you want performant dispatch, Clojure can
give you JVM-level perf through the use of protocols. If, however, you want
input validation (in the sense that you can be sure that a function argument
you've been given will allow you to do what you intend with it) then static
typing isn't the only player in that game.

In my experience (which I think resonates with RH and most Clojurists) is that
for the vast majority of _information-driven_ systems, types are used as the
latter. If you have a `Customer` class that gives you guarantees about the
availability of, say, an `accountNumber` field, that is useful for correctness
as you can be sure the information you need is there. However, if some future
downstream coder wants to use your customer in the more general sense of being
a human, then (s)he has to worry about sub/super/abstract-classing, may have
to make upstream modifications to expose previously hidden data, and similar
faffage. In Clojure the idiomatic solution to this problem is to "just use a
map"; the real-world downside to this, however, is extremely weak contracts
between functions. In this example, what `spec` allows you to do is strengthen
those contracts by verifying that the data your function is provided is
sufficient for your uses (as in the map contains all the keys you'll need with
suitable data types in the fields) _without_ constraining what downstream
consumers can also do with this data (extra map keys are ignored).

These checks are only done at runtime and only when enabled, however writing a
spec gives you (very-nearly-almost) free generative testing that will run your
function a default of 1000 times with random data in the correct shape to make
sure it doesn't blow up—this isn't a guarantee of correctness, but it does
provide extremely high levels of confidence (most type systems are also not
even close to guaranteeing correctness either, only compliance with the type
system). Spec also gives you (for free) performant runtime coercion for use in
actual real-world code. You get a lot of bang for your buck.

`spec` is definitely not a type system, but it very capably fulfils a similar
role in the kinds of programs Clojure was intended to be good at. It gives you
all the flexibility and dynamism of Clojure with most of the confidence of
static typing, without constraining either.

~~~
_bxg1
> by verifying that the data your function is provided is sufficient for your
> uses (as in the map contains all the keys you'll need with suitable data
> types in the fields) _without_ constraining what downstream consumers can
> also do with this data (extra map keys are ignored)

This assumes a very class-oriented type system. Duck-typing and the like don't
have the upstream ontology problems.

My main desire from types is as an iteration assistant (with editor
integration). Even if I wrote a function myself, I may not remember the exact
order of arguments, or the exact name of that one property on the returned
map. I want to a) be able to quickly peek and see what those things are -
either by visiting the definition or, even better, via a pop-over in my editor
- and b) have my editor tell me immediately if I did something dumb so I can
correct it and keep moving.

In a dynamic language, whenever I need to double-check the contract for some
code, I can't just go look look at its type signature, I have to go _read
through_ it. I have to fully load that whole subtree of information into my
brain (recursively to any functions it may itself call), when I'm really
trying to focus my thoughts on something else. This can be a huge, needless
drain on mental resources.

Spec would help with this some, assuming the author follows a good convention
of putting all of their assertions at the top of the function. But maybe those
assertions are done inside conditionals, creating a more complex type. And
maybe my editor doesn't know what to make of them (do any editors? genuinely
curious). Etc. It just creates a bunch of little speedbumps to cognition that
add up.

~~~
lorddoig
> In a dynamic language, whenever I need to double-check the contract for some
> code, I can't just go look look at its type signature, I have to go read
> through it. I have to fully load that whole subtree of information into my
> brain (recursively to any functions it may itself call), when I'm really
> trying to focus my thoughts on something else. This can be a huge, needless
> drain on mental resources.

Yes, this is a headache, and certainly a problem that afflicts Clojure. Spec
doesn't really help much in this regard. There is a proper static typing
system for Clojure[0] that does provide a lot of the editor integration you
speak of, but as I recall it was a little too brittle and orthogonal to
Clojure's way of doing things to be as useful as spec. Some of Clojure's core
constructs are completely impossible to type statically.

As with everything there are tradeoffs and choices to be made. I've been
writing Clojure professionally for 5+ years now and there's no other language
I have much interest in dealing with full-time (yet). One has to choose one's
poison I suppose.

    
    
      [0]: https://github.com/typedclojure/typedclojure

------
d_t_w
This is superb, and I'm only on page two. I'm thankful that Rich finds the
time to produce his thoughtful content and I hope he has the opportunity to
present this at HOPL-IV when it is rescheduled.

The distinction between Information Systems and Artificial Systems is the key
point to me and reflects my experience, not that I understood it at the time.

I use Clojure today because it is a better thinking toolkit for Information
Systems (or the inelegant 'Products' as I defined them in my conj talk). I'm
an order of magnitude more productive in Clojure than I was in Java. It's not
a small step, it's a step-change.

------
zrkrlc
All right. That's it. I'm porting over all my code to Clojure.

Any tips to get me started? I'm writing a web app to process DAG-formatted
data.

EDIT: Looking at re-frame + reagent 'cause I have some React background. I
also found The Joy of Clojure and Elements of Clojure from other threads.
Anything else I should know before diving in? (Past experience: Haskell,
Python, C#, JS)

------
agentbellnorm
Sometimes when we have created things with code, we wipe the sweat from our
foreheads and feel proud because it was kind of hard.

Usually when I have created something with clojure I feel disappointed because
it was so easy.

------
mikmoila
Co-routines: Java has project Loom coming very soon, which (IMHO) shows the
way how it should have been done.

~~~
spacemanmatt
I'm really looking forward to this getting to production quality. I have a lot
of code that will benefit immediately.

------
stormdennis
So would clojure work as a substitute for scheme to go along with the sicp
book?

------
ggregoire
Is there any statically-typed FP language with Lisp's parenthesized syntax?

~~~
bmitc
Typed Racket is one option: [https://docs.racket-lang.org/ts-
guide/](https://docs.racket-lang.org/ts-guide/)

I'd say also that the ML-dialects, such as F#, Ocaml, and SML, are pretty
close to a statically typed Lisp/Scheme, at least in the flavor of programming
aside from them having better pattern matching built-in.

I'd like to see a specifically designed statically typed parenthetical
language, basically something that merges Racket and F# but simplifies things
a bit.

------
hefner
Cool!

