
Clojure will affect the way you think about programming - ingve
http://eli.thegreenplace.net/2017/clojure-the-perfect-language-to-expand-your-brain/
======
keymone
Clojure is the language where LISP clicked for me. Can't recommend it enough,
it's got all of it - immutable datastructures, convenient data literals,
simple and composable concurrency primitives, very thin interface to host VM.

Just put enough effort to get beyond that "omg parenthesis" barrier and it
will be a delight. It's like that Half-life joke: there are two kinds of
people, those that finished Half-life many times and those that never got off
the train (which as somebody will probably point out, is a variation on
another joke, but you get the idea).

totally unaffiliated: [https://www.braveclojure.com/clojure-for-the-brave-and-
true/](https://www.braveclojure.com/clojure-for-the-brave-and-true/)

~~~
arximboldi
There are many things to love in Clojure, like core.async, the lispyness, etc.
But for me, their biggest breakthrough is with no doubt the data-structures.

Clojure default of immutable hash maps and vectors was really bold. They had
to innovate by giving a twist to Bagwell's great research on data-structures,
and they managed to build what in my opinion are the first set of general
data-structures suitable of representing traditional hierarchical object-tree
data-models immutably, at the scale of large interactive software.

Without these, the single-atom architecture that now is popular as ever with
Redux, Elm, etc. would not be possible. The flourishing of functional
programming for interactive software that followed shows to me that the
biggest impediment before was not the lack of functional ways of expressing
interactions (the Haskell people have devoted a lot of notable effort in the
FRP camp). Instead, just having efficient data-structures to write persistent
document models, escaping the rigidity of lists and rb-trees, allows you to
write big interactive sofware in a functional manner even with the most dumb
abstractions (which is a good thing, KISS!) and even stupid language
(JavaScript!).

This has inspired me to work on a generic implementation in C++, which also
has experimental Python and Guile bindings:
[https://sinusoid.es/immer/](https://sinusoid.es/immer/)
[https://github.com/arximboldi/immer/](https://github.com/arximboldi/immer/)

In the past I also did some other work on bringing Clojure Transducers to C++
([https://www.youtube.com/watch?v=vohGJjGxtJQ&t=1614s](https://www.youtube.com/watch?v=vohGJjGxtJQ&t=1614s))
but I know consider it a much less important effort---without the data-
structures the other parts of Clojure feel almost like just sugar.

EDIT1 -- Sorry for the shameless plug ;)

EDIT2 -- Grammar

~~~
tome
Do you know of a good resource for reading about their data-structures,
especially anything Haskell doesn't have?

~~~
DigitalJack
Any book on clojure and website too will go over them. They are fundamental to
using clojure.

I don't know enough about haskell to say what it does or doesn't have in
relation to clojure. However, it's not simply the data structures, but how the
language is built to interact with them from a programmers perspective.

From a user interface to the language point of view, I find the ways of
interacting with maps to be very nice.

In particular the dual purpose of "keywords" to serve both as a good index/key
in said hash maps, but also as callable look up function for the same key in a
hash map leads to simplified code.

This, coupled with the extremely high usage of those maps in typical clojure
code, makes a big difference.

To expand on that a little, "keywords" are symbols that begin with a colon,
which I believe is the same as common lisp. :for :example :this :is :a
:sentence :of :keywords. They are commonly used as the key in a map. Which has
a literal syntax like (def map1 {:a 1 :b 2 :c "taco"}). To pull a value out,
you can evaluate (:c map1) which will return "taco".

They are hash maps based on work by Philip Bagwell, and I think a lot of
languages have versions of this now. At least scheme and Common Lisp do. But I
don't believe they have the nice literal syntax and interaction syntax.

Many Lisp traditionalists are bothered by the use of curly braces for maps and
square brackets for vectors, however I'm a fan. Without this bit of syntax,
you have to add verbosity to the language to differentiate defining a map from
doing a lookup, etc.

For resources, Clojure for the Brave and True is pretty popular. Also the
online community is quite friendly, although I have noticed some trends toward
"the one true way" of doing things that puts me off a little.

~~~
madmax96
>Many Lisp traditionalists are bothered by the use of curly braces for maps
and square brackets for vectors

I have definitely seen this. I'm not sure that I understand this sentiment.
The only thing that Clojure is missing is the "system" feel that Common Lisp
provides, with things like character macros, symbol macros, etc.

That being said, I definitely appreciate how thought through Clojure is,
especially when compared to CL. Several things are missing/don't feel well
thought out in CL (notion of a `calleable` type is gone, `nth` isn't defined
on vectors or strings (but you can still `length` them!) nor is `first` and
`rest`) That provides a great deal of friction.

~~~
lispm
Common Lisp had a lot thought put into it, but the design goals were
different. One of the design goals was to support efficient compilation given
various constraining dimensions: the need for speedy compilers vs. the need
for delivery of applications on standard hardware. Thus a Lisp compiler should
be able to generate fast code, even by using whole-program compilation. Thus
the language has to take care of a wide range of possible implementations, not
just one on a particular virtual machine.

Clojure OTOH has a relatively straight-forward compiler written in Java, only
targetting the JVM in a standard way. The Java/JVM infrastructure for code
generation (JIT), low-level optimizations (JIT), memory management,
application building and delivery could be reused. With all its features and
limitations (for example no TCO, fixed JVM instruction set, ...).

Common Lisp also not only provides some generic operators, but also lots of
non-generic operators. One reason for that is the will for backwards
compatibility (which was another goal in the Common Lisp design) and the idea
that something like Common Lisp is also a low-level languages or provides at
least a layer of low-level stuff, functions you would use to implement higher-
level stuff.

Common Lisp is the next step in the evolution of Lisp I to Lisp 1.5 to Maclisp
to Zetalisp. Thus it contains much of the core Lisp functions, stuff you can
read about it the Lisp manuals from 1958 and 1960. People did not want to
throw their code away, they wanted a modernized Maclisp. Thus one could port a
100kloc Lisp program from Maclisp or Zetalisp to Common Lisp without too much
effort. The main operations were there.

Clojure OTOH has almost no backwards compatibility to earlier Lisp dialects.
Programs can not be ported from Lisp to Clojure in a useful way. They have to
be rewritten. But that was okay, since the main target were not Lisp
developers, but people who wanted a language with Lisp influence in the
Java/JVM eco-system (or possibly other eco-systems too).

Thus Common Lisp looks to you like it has less thought put in, where people
actually struggled to be backwards compatible and modernize the language at
the same time.

So Common Lisp has lots of non-generic functions, a layer of generic non-
extensible functions (like the sequence layer) and a mechanism for extensible
generic functions (CLOS). Something like CLOS is implemented on-top of the
non-generic Lisp, with a few parts using implementation specific mechanims.
One does not need to use the primitives of a different host language, because
Common Lisp is already capable of hosting with its primitives.

------
vosper
Having spent some time programming in Clojure, for the purpose of expanding my
brain, I suspect a better Lisp to start with might be one of the classics -
Racket, Common Lisp, etc... One of the reasons I gave up on Clojure was the
lack of documentation of libraries, the bad debugging experience (those stack
traces!) and the fact that there's no avoiding the JVM. They're all
distractions to the learning (that was 2 years ago, I'd be happy to hear that
things have changed).

I think Clojure is a great language, but if you just want to expand your mind
via a Lisp then I think you'll get more for your time with another
implementation.

~~~
totalperspectiv
I agree. I read through Clojure for the Brave and True, and played with it a
bit, but it was too much new stuff at once coming from an only Python
background.

I'm reading Structure and Interpretation of Computer Programs right now and
everything is clicking. I'm looking forward to going back to Clojure after I
get through more of SICP.

~~~
DigitalJack
Many people say that clojure is the one that clicked for them, but I suspect
it's really not due to clojure itself, just that it's more recent and likely
not to be the first lisp people have tried to learn.

I think the exposure of trying to learn different lisps is the key, and when
you get to a point where one clicks, run with it!

------
shadowmint
I don't like working with clojure.

Its basically modern perl. I've worked with both professionally, and the
outstanding point with both has been:

\- programmers try to be clever in their code, write one giant file full of
complicated specialized 'beautiful' code, forget everything they know about
breaking big tasks into simple small ones.

\- code is a nightmare to maintain for non-author

\- non-authors working on code results in adhoc mess of styles

Play with, sure. Learn a few things and watch the videos, absolutely. Rich is
a really thoughtful talker. I actually quite enjoyed clojure before I had to
collaborate on a code base.

...but goodness me. I cannot strongly enough recommend against using it
professionally.

~~~
KirinDave
Are we doing opinion threads now? Okay. I can do one too!

I do like working with clojure. It's my favorite dynamically typed programming
language by an easy margin.

It's basically everything that was a good idea in Python and Ruby brought
under the unifying role of a Lisp syntax, with a good Java FFI. This makes it
slightly harder to learn (it's very difficult to learn Clojure if you don't at
least know Java).

It has a very clean syntax for the most part. Parenthesis handling does need
some automation (basically everyone copied paredit) but has the nice property
that refactoring is a breeze and extremely predictable.

Except for rogue agents like me and a few others, very few programmers go
crazy with defmacro, which makes Clojure often a lot more orderly and
understandable than lots of Common Lisp code.

I've run a shop with 6 clojure developers collaborating with engineers in both
mobile and web space, and in many places Clojure was such a delight that cljs
began to creep into the web frontends. In many cases the mobile devs
contributed API endpoint handlers to the codebase and they said in general it
was easy to work with (although folks sometimes had problems with more complex
map types; often because of leftover code from the Bad Old Days when :symbol-a
and :symbol_a both got introduced into our codebase because of bugs in AWS
bindings choking on -'s).

Clojure, like many dynamic languages, is ultimately limited by its lack of a
type system. At some point systems become challenging to refactor. To combat
this, a lot of discipline about testing and builds needs to happen.

I built a business around Clojure, sold it to a bank, and made lots of money
and friends along the way (and just yesterday the bank announced they have
decided to kill it because they don't like it, but that's got little to do
with clojure and everything to do with <REDACTED>). We did stuff that VCs flat
out claimed was impossible, to my face.

I'm much more interested in other languages now, but that's not because I
think Clojure is bad. It's because I think that my development as a software
engineer requires I put Clojure down for a few years and work with other
concepts.

~~~
bhnmmhmd
>> ...the bank announced they have decided to kill it because they don't like
it, but that's got little to do with Clojure...

I think that had something to do with Clojure. The thing is, businesses
usually follow best-practices and choosing a language like Clojure is
certainly not a best-practice (even if developers had really good reasons to
use it).

For example, who maintains the code? How many Clojurists (is that a word?) can
you find to work on the project? The bank would be better off by sticking to
Java/Python/C#/etc.

Just because you can do it, doesn't mean that you should. That's a bad habit
I've seen from many developers (honestly, I understand the interest to learn
more languages and use them at work, but that often results in short-
sightedness when building a project).

~~~
KirinDave
> I think that had something to do with Clojure.

Were you on the Level team at Capital One? If so, oh hai and I hope all is
well. Given all the changes there, you may want to be careful. You gotta know
this is against policy if it goes much further. I know because I got in
trouble over violating said policy once... If not: no. You're wrong. Headcount
issues were largely unrelated to Clojure. Also, please stop pretending your
best guess is some sort of calculus over complex corporate politics.

Staffing as a small startup bought by a big company is always a problem.
Doubly so when you're on the leading edge of a corporate introduction into a
new (and in many ways more fiercely competitive) labor market.

> can you find to work on the project? The bank would be better off by
> sticking to Java/Python/C#/etc.

I had no problem recrutin good clojure developers once I worked with the
recruting team to help get the job postings in the right places.

> Just because you can do it, doesn't mean that you should.

The converse of this that is equally true: Just because you don't feel capable
of doing it doesn't mean I should not. This is no idle speculation, we _did_
it. We exited. We exited with a featherlight team, which turned a small and
interesting project into a major opportunity for every employee.

~~~
bhnmmhmd
> ... Also, please stop pretending your best guess is some sort of calculus
> over complex corporate politics...

I think you should try to be more civil on HN. You can't just bash someone
because of their _guess_.

> The converse of this that is equally true: Just because you don't feel
> capable of doing it doesn't mean I should not.

I don't want to get into some argument with someone who feels he is the _only_
guy capable of achieving a failure.

~~~
KirinDave
> I think you should try to be more civil on HN. You can't just bash someone
> because of their guess.

I asked politely, my friend. I'm suggesting your guess, leveled as an
authoritative position, is misleading. Its you, taking my story away from me,
asserting your narrative based strictly on preference. It's a narrative I
disagree with, so I'm not inclined to let it slide.

It's crass to do this. There are many, MANY other ways you could have decided
to open this subject. You could have related to YOUR experience, you could
have asked for explanation of how these problems are perceived or surmounted.
You could have simply expressed skepticism about the team size.

But you didn't. Here we are, on the wrong foot.

> I don't want to get into some argument with someone who feels he is the only
> guy capable of achieving a failure.

Then worry not! I am not: a guy, the only one capable of achieving, nor do I
consider the product that made me a millionaire a failure.

------
sharms
I have switched between many programming languages, and if you are considering
Clojure I would highly recommend it. It is immutable first, which helps
eliminate many classes of explicit bugs and non-obvious anti-patterns. It also
works across Java / Javascript allowing for a common code base of business
logic across all layers, and with React Native looks and performs well on iOS
and Android.

~~~
hsx
When you say it works across Java/JavaScript - could you expand? Can I
essentially write Clojure that compiles to JavaScript?

~~~
yogthos
Clojure uses reader conditionals
[https://clojure.org/guides/reader_conditionals](https://clojure.org/guides/reader_conditionals)
that allow writing code that cross-compiles between different platforms, and
generates platform specific code when necessary.

Many Clojure libraries cross-compile between Clojure and ClojureScript. You
can see an example here [https://github.com/yogthos/json-
html/blob/master/src/json_ht...](https://github.com/yogthos/json-
html/blob/master/src/json_html/core.cljc)

------
lispm
> Clojure is a dynamic language.

Dynamically typed. As a dynamic language Clojure is less capable than many
other Lisp implementations/languages. See for example 'late binding'. In
Clojure you either need to define a function before its use or need declare
it. Not that 'dynamic'. In a typical Lisp dialect the order of definitions
makes much less a difference, since functions can be called late-bound. For an
interpreter-based implementation, it makes no difference at all.

> It promotes combinations of built-in data structures (lists, maps, vectors)
> over objects

An aspect I don't like. This makes debugging of larger systems more difficult,
since maps are maps. Whereas objects have a type tag built in, have a list of
allowed fields, etc. etc. They simply have more more explicit and standardized
structure to them.

> Some built-in features like reducers and transducers rely heavily on
> composing higher order functions for transforming other functions.

Which makes code complex, since transducers are a mildly complex mechanism.

> It encourages REPL-based development

In relatively weak form. Basic features of Lisp need to be added to do simple
tasks: like 'instrumenting' code to debug it, since it lacks an interpreter or
more capable compiler support. REPLs with actual interactive error handling
are not standard. Interactive Lisp compilers like the one from SBCL give much
more information and warnings.

Thus the Lisp development features are at best only medium-level.

> Historically, Lisp programmers weren't the biggest proponents of OOP

Funky, people from the Lisp community helped to shape OOP and explored much of
it. From guys like Hewitt who developed the actors paradigm in the early 70s,
Minsky who developed the frame theory mid 70s and inspired a whole range of OO
programming in Lisp, to Howard Cannon who developed Flavors in 1979 with
flexible mixins and multiple inheritance used to implement the object-oriented
operating system parts of the MIT Lisp Machine, to Lieberman who developed OOP
with prototypes mid 80s, to Kiczales who worked a decade on OO in Lisp (LOOPS,
CLOS, Meta-object Programming, Object-oriented Protocols, Meta-level
architectures, early Aspect oriented programming, ...).

Actually objects in the early Lisp were simply symbols with their property
lists. These property lists could hold both normal attributes and also
functions.

~~~
weavejester
> An aspect I don't like. This makes debugging of larger systems more
> difficult, since maps are maps. Whereas objects have a type tag built in,
> have a list of allowed fields, etc. etc. They simply have more more explicit
> and standardized structure to them.

You can create explicit and standardised structures for maps in Clojure, or
indeed any other data structure:

    
    
        (s/def :foo.student/name  string?)
        (s/def :foo.student/score nat-int?)
        (s/def :foo/student (s/keys :req [:foo.student/name :foo.student/score]))
    
        (def example-student
          #:foo.student{:name "Alice", :score 30})
    

However, Clojure takes a somewhat divergent philosophy, as it encourages
writing schema for individual fields, rather than a schema for a grouping of
fields (such as an object).

For example:

    
    
        {:foo.person/name "Alice"
         :foo.student/id  "xyz123456"}
    

The namespaces of each keyword are different, but they're grouped in the same
map as they happen to refer to the same entity.

So rather than operating on a fixed type like `Student`, a function would
request that it requires a data structure that has a person's name and a
student ID:

    
    
        (s/fdef enrol
          :args (s/cat :student (s/keys :req [:foo.person/name :foo.student/id])))
    

We're still validating (albeit dynamically), but we can be more flexible in
what data we ask for. This ties in with Clojure's idea of simplicity; a
function shouldn't know about data it doesn't intend to use.

~~~
lispm
> standardised structures for maps

Then there are defstruct and deftype. So it has maps, struct-maps, records,
deftypes, Java classes, ... a whole bunch.

'simplicity'?

> This ties in with Clojure's idea of simplicity; a function shouldn't know
> about data it doesn't intend to use.

I would use a class for that, since something like CLOS supports multiple-
inheritance and all the necessary mechanisms for mixins.

Finding these methods then is supported by the organization in generic
functions and hierarchical classes.

~~~
weavejester
> Then there are defstruct and deftype. So it has maps, struct-maps, records,
> deftypes, Java classes, ... a whole bunch.

defstruct has been deprecated for years. deftype and Java classes are
primarily for JVM interop and language extensions.

Outside of calling Java libraries there are just maps, which you're going to
be using 95% of the time, and records, which are maps with efficient
polymorphism.

> 'simplicity'?

In Clojure parlance, "simplicity" refers to interconnectedness. So a box of
tools is "simple", because they're not connected, whereas a Swiss army knife
would be "complex", even if it might be easier for a novice to use.

Having a bunch of similar tools isn't complex, from Clojure's point of view,
as long as they're separate. It may make things more difficult to learn, but
that's another problem entirely :)

> I would use a class for that, since something like CLOS supports multiple-
> inheritance and all the necessary mechanisms for mixins.

Doesn't that mean you'd need a separate class for each way you access the data
if you wanted to type that? My knowledge of CLOS is, I'm afraid, rudimentary,
but can you say to a method: take as as argument an object that has the "id"
field from the "Student" class, and the "email" field from the "User" class.
Or would you have to explicitly pre-define mixins like HasStudentId and
HasUserEmail?

~~~
lispm
> In Clojure parlance, "simplicity" refers to interconnectedness

Clojure tends to redefine words describing concepts with a new or restricted
meaning. Typically a general concept like 'simplicity' would have more than
one dimension.

> take as as argument an object that has the "id" field from the "Student"
> class, and the "email" field from the "User" class. Or would you have to
> explicitly pre-define mixins like HasStudentId and HasUserEmail?

I would not do this at all. Having slots or not are low-level artefacts and
writing methods which are fine-grained to slots of an objects don't expose the
domain-level.

I would use methods for domain level classes which have the necessary slots
either local or inherited.

~~~
weavejester
> Clojure tends to redefine words describing concepts with a new or restricted
> meaning. Typically a general concept like 'simplicity' would have more than
> one dimension.

Sure, but that happens all the time in programming. When we talk about
"objects" we don't mean "a material thing that can be seen and touched".

> I would not do this at all. Having slots or not are low-level artefacts and
> writing methods which are fine-grained to slots of an objects don't expose
> the domain-level.

I guess because it's not at all idiomatic, even in an object system as rich as
CLOS.

But in Clojure it _is_ idiomatic, and to my mind it leads to a more precise
definition of what a function wants. We don't say, "this is a method that
operates on a Student object"; we say, "this is a function that takes data
that includes a student's email and enrolment date".

Again, I hasten to add that my experience with CLOS is virtually non-existent,
but compared to the OOP languages I _am_ familiar with, Clojure has a far
richer way of describing the structure of data.

~~~
lispm
I understand that, but as I said I don't like that at all. It binds methods to
low-level adhoc features and not to class based domain ontologies. There are
other pattern directed invocation systems, which also support that, but I
usually prefer the more systematic approach of CLOS. In the tradition of
symbolic programming I want to have symbolic classes as my anchors for
functionality, not adhoc patterns.

~~~
weavejester
You can still create class-like ontologies with Clojure specs, but usually you
don't need to.

Clojure's specs, adhoc or otherwise, certainly might not be your cup of tea.
Clojure really pushes the idea of separation and isolation, and in my view you
need to buy into that philosophy to be at all comfortable with the language.

Where I disagree with you is your assertion that maps in Clojure are always
less structured than objects. I'd claim that (at least when properly spec'ed
out) they provide far _more_ structure than objects.

~~~
lispm
I'm not talking about what is possible or what _can_ be done. I'm talking
about what is natural and promoted. See the message the article communicates:

> It promotes combinations of built-in data structures (lists, maps, vectors)
> over objects

I would say that this is actually the case and this article is not the only
one to say that.

~~~
weavejester
Yes, but as I said, using data structures over objects doesn't mean the data
is unstructured. You can use lists, maps and vectors and still have a well
defined and validated structure.

------
didibus
I started learning Clojure two years ago, and it has expanded my brain in many
ways. I love Clojure for the pure joy it gives me on a daily basis.

In those two years, it thought me about:

    
    
      - Interactive programming
      - Persistent data structures
      - Immutability
      - Code that writes code
      - Functional programming 
      - Extendable polymorphism
      - Lazy evaluation
      - Eager evaluation
      - Parallel computing
      - Dynamic variable extent
      - Recursion
      - Concurrent programming
      - Declarative programming
      - Aspect oriented programming
      - Logic programming
      - Code as data
      - Software transactional memory
      - Generative testing
      - Contracts guards
      - Optional type systems
      - Conditional restarts
      - Monads
      - Variant types
      - Collection abstractions
      - Array programming
      - Map Reduce
      - List comprehensions
      - Reactive programming
      - S-expressions
      - Destructuring
      - Pattern Matching
      - Prefix operators
      - Closures
      - Data literals
      - And more...

------
cderwin
If "expanding your brain" is really what we want to optimize, why not learn
Haskell? Or for that matter, why not learn something even more strongly typed,
like Agda or Idris? Or even a theorem prover like Lean?

Most of the reasons the author presents would either be expanded in one of
those languages, or is immaterial to the goal of maximizing learning. After
reading the article I have no more reason to consider learning Clojure over
learning any of the languages above.

~~~
yogthos
One huge difference is the workflow you have in Clojure. REPL driven
development is an experience unique to Lisps. When you're working with
Clojure, any code can be run in the context of the live app straight from the
editor as you write it. This is an amazing experience and very mind expanding
in what a development process can look like.

Also, anybody who wants to try FP style programming, but isn't interested in
static typing is much better off with Clojure. Type systems in languages like
Haskell and Idris add a lot of complexity and mental overhead that's not
present in a dynamic language.

~~~
drawnwren
Is there something about clj's repl that makes it any different from ghci's?

~~~
yogthos
Yes, you can reload any symbol in the CLJ REPL directly from the editor. You
can also evaluate any function within the context of the running application
without going through the main. The REPL is an integral part of the
development process in Clojure. You can see this in action here around 15
minute mark
[https://www.youtube.com/watch?v=nItR5rwP4mY](https://www.youtube.com/watch?v=nItR5rwP4mY)

~~~
dracodoc
R and RStudio are actually quite good in this aspect.

\- You can evaluate any part of editor in console with keyboard shortcut. The
only difference between using console and editor is that your input is easily
saved in editor.

\- The environment browser make inspecting variables, data structures much
easier.

Besides, in R you want to use vectorized functions for better performance, so
you search for general functions and combine them, which actually promote good
functional programming style instead of a big control block with many
processes intertwined.

------
davedx
I have to say after diving into ClojureScript I came away thinking differently
about a number of things - state management, _how_ to program functionally
when you are more constrained than in more permissive languages. It was a real
learning experience.

~~~
hannofcart
This ^ right here, is what gets lost in all the squabbling over functional
purity and parenthesis hate.

For a huge number of developers coming from the Javascript/web side of things,
Clojurescript is poised so perfectly to usher them into thinking about
composing your programs as pure functions, immutable data structures and
organizing your state such that it is easy to reason about.

Eventually, Clojure led me to Haskell, and even back to how Javascript ought
to be written (i.e. fantasy-land specs). This has been the single most eye
opening learning effort that I have ever had the joy of undertaking since I
started programming.

------
escherize
Nothing I've used has the combination of ease of use and interactivity. It's
pretty difficult to explain, but one can send both top level forms, or smaller
pieces of code to the repl and get results without leaving the code one is
working on.

[https://s3.us-
east-2.amazonaws.com/photoblobs/screencast_201...](https://s3.us-
east-2.amazonaws.com/photoblobs/screencast_2017-08-04_09-03-37.mp4)

------
bachmeier
I would love to use Clojure (it's probably the only language I would consider
moving to right now) but the JVM just doesn't work for me. Clojure-native that
offered all of Clojure and was realistic - there was one that indirectly used
Gambit Scheme at one time, and an incomplete Python version - would be
awesome. Clojure that requires you to use the current Java approaches to
interfacing with C is not of interest.

~~~
DigitalJack
I've felt that way about clojure native, but what makes a language is the
ecosystem, and the JVM brings a fantastic ecosystem.

There really is no way to offer "all of clojure" as native because the
ecosystem is part of what "all of clojure" offers.

I've long thought about ways of doing a "native" clojure, and have eventually
come to the conclusion that it doesn't offer anything compelling.

If you want fast start up time and scripting, you can do that with node and
clojurescript. Or Lumo or whatever else there is in that area.

Once running, the JVM is pretty performant in a lot of cases... Where it
struggles are where all garbage collected languages struggle. If that's the
pain point, you could probably bootstrap a scheme from Gambit or Chicken that
did manual memory management...I struggle to imagine what that would look like
in the end though. Lisp flavored C maybe.

People smarter than me have said that the Clojurescript compiler is an
excellent starting point for making a compiler that emits other languages.
It's over my head, but maybe it would be a worthwhile project to emit golang
or something.

I believe some of the clojure-schemes that floated around briefly bootstrapped
from clojurescript compiler to emit Gambit Scheme...

Without the libraries/ecosystem I don't think it would be worth it.

~~~
bachmeier
> the JVM brings a fantastic ecosystem

Unfortunately it's (intentionally) horrible for interfacing with C libraries.

> it doesn't offer anything compelling

Unless you need to interact with native libraries.

There's currently a lot of excitement about Scala Native and Kotlin Native.
Those projects aren't being done just for the heck of it.

~~~
DigitalJack
A lot of projects are done for the heck of it. Nothing wrong with that.

Native libraries is a good reason. Particularly GUI libraries.

I imagine Swift would be a decent target for a lisp, for app development.

GUI is a major missing area in clojure. There are some good efforts there,
Seesaw targeting Swing, and fn-fx targeting JavaFX.

------
swlkr
Clojure also affected the way I think about programming in a very positive
way. There are downsides to it

\- stack traces \- jvm \- lein is pretty slow

but the upsides

\- immutable data structures \- lisp/macros \- repl (you can send code from
your editor to the repl) \- community \- great open source web app libraries
(for me, anyway)

outweigh the downsides.

I encourage everyone here to try clojure at some point, it might just become
your favorite language.

~~~
cnlwsu
For people familiar with java, the jvm is an upside. Being able to use
libraries (especially client ones) from your project can be very useful. The
amazing interop support is very nice if your pragmatic over purist and don't
plan on rewriting a ton of things.

~~~
swlkr
This is true, if you're a java/jvm person, this is a huge upside, even if you
aren't, once you see just how much code has been written in java, you'll
probably come to appreciate the pragmatism.

When I learned clojure two years ago, I didn't have any experience with java
or the jvm, so I had to sort of learn where the boundary was.

After that initial hurdle however, I now use java interop quite a bit.

------
jrs95
I just saw an article recently about core.async and the "go" macro, which
seems to effectively give you goroutines in Clojure. I'd be very tempted to
use it for that reason alone. I love Go's concurrency, but it can be a little
on the verbose side. Good for some projects, but not all of them.

~~~
eliben
Go is _verbose_? I'm surprised to hear that, to be honest. Can you say what
it's verbose in comparison to? What production language/framework has terser
concurrency with the same expressiveness?

~~~
robto
Clojure for one! But I thought it was a common complaint that Go's lack of
support for generics and other language design decisions aimed at keeping
things easy make it much more verbose.

That's just a non-user's perspective on the scuttlebutt, though - I don't have
any actual experience with Go.

------
niix
I was fortunate enough to be given the opportunity to learn Clojure on the
job. A majority of my work is on the web side (JavaScript, et al.), so
learning Clojure was a fun and interesting challenge.

After the initial hurdle of getting used to a Lisp I found the language very
liberating. I definitely approach problems very differently than I did prior
to learning Clojure, even when flipping back to JavaScript land. I find my
approach is vastly different that it was before. The best way to describe my
way of thinking is that I'm very "data first" now.

------
iterati
I was lucky enough to land a Clojure job (stitchdata.com, we're hiring!)
before having to learn Clojure, because I had the benefit of experienced
mentors helping me get to grips with lisps (which were alien to me) and a
development workflow that leaned heavily on the REPL (emacs + cider). Clojure
has changed the way I think about many programming concepts and has been a joy
to learn. It has it's warts but the core is very well built and I find the
documentation to be quite good once you understand the basics.

------
delegate
I agree with the article, but would also like to mention that it has a very
steep learning curve.

1.5 months after my first line of Swift I had my app in the app store (granted
I was proficient in Objective-C). 2 years since I've started learning Clojure
and a couple of months since I'm working professionally with it and I'm still
quite shaky.

Luckily, it's not difficult to begin - you can start hacking small programs in
a couple of days, but when it comes to building large applications, that's
when it becomes a high-level art form (just one of the many possible metaphors
:) ).

Quite similar to C++ in this respect - easy to pick up, hard to master.

It humbled me and made me cry many times. But as with everything, if you don't
give up, you level-up.

As far as the experience goes, it gives you this 'overview' experience of
programming - you can mimic almost any feature from other languages and you
have access to all the libs for the JVM (including C/C++ libs through JNI)
plus all the javascript libs.

So in terms of libraries you can use, I dare say that Clojure(script) is the
language which can access the most libs out there.

So yeah, definitely a powerful language and a powerful tool which you can go
very deep into, albeit a bit tough to learn.

~~~
droidist2
It's a bit of a change from most mainstream languages, but still way easier
than Haskell though.

------
hellofunk
> core.spec makes it more formal and verifiable. This is very useful when
> working with data, and is another example of where Clojure's pragmatism
> shines; the language is dynamic in its core, but when you need static typing
> - it's there, optionally

Um no. Spec is not static typing, it does runtime checks. And core.typed is
currently being rewritten and is not compatible with current version of
Clojure.

------
chpill
I have been working with Clojure(script) full-time for the past 4 months
(coming from javascript). I highly recommend it. Programming is fun again.

------
extra__tofu
I'm an EE who is getting more and more interested in software development and
computation in general. I've been reading Paul Graham and Peter Norvig and
decided to learn Scheme. Any thoughts on Scheme vs. Clojure for learning?

~~~
twfarland
Scheme is a smaller language and has legendary beginner books. Start with HTDP
and then SICP.

~~~
peatmoss
Seconding HtDP. I have gotten lots of mileage from that one.

------
moomin
Clojure will affect the way you think about programming. It's led a number of
people I know to start taking Haskell seriously after their Clojure phase.

~~~
lgas
This seems somewhat surprising to me since they are, in some sense, at
opposite ends of the functional programming spectrum... but it's the path I
took.

~~~
moomin
I think it's a cultural thing. There's something similar going on with Python
and go.

Seems like a lot of people start with "getting types to go away makes a lot of
powerful things easier". But eventually you a) get sick of typos causing
runtime errors b) start to realise there are even more powerful things you can
do with a non-broken type system.

------
lngnmn
Why not Common Lisp or Scheme?

~~~
cgore
I did Common Lisp back in college for several years, it's a great language.
But good luck getting a job with it. Clojure on the other hand, I've been
paying my bills with that for the last few years. The main difference is a
much larger community, and therefore lots more libraries for real-world stuff,
and sitting on the JVM you have a lot of options integrating with existing
corporate stuff.

~~~
agentultra
There's a Common Lisp implementation that sits on the JVM. It's called ABCL.
It provides a Java API for loading and calling Lisp code as well as a Lisp API
for calling Java code (although it is quite a bit more verbose than that
provided in Clojure... nothing a few macros couldn't solve if it became a
nuisance).

The community is what does it. I tried for years to get commercial work in
Common Lisp. It never happened.

------
hellofunk
By far the most incredible thing for me was to see how far a few characters of
code can go. Clojure is a very tight language where you can accomplish a lot
in just one line of code. You end up suddenly having all this new, extra time
to just think about your problem instead of coding it.

~~~
yogthos
Another interesting side-effect of tight code, is that you become a lot less
attached to it. When I worked in Java, it would often take 100s of lines of
code to solve a simple problem, and once I wrote that code I'd be very
hesitant to throw away or refactor it.

With Clojure, it often takes 10 lines or less to solve problems that take 100s
of lines of Java. This encourages a lot more experimentation and refactoring
in my experience.

Also, since you're always working in the REPL, you can always run the code
after you change it and see that it's doing what you want immediately.

~~~
macintux
The functional nature helps with the lack of fear of refactoring. Your Java
code may have side effects reaching across the code base.

------
marklgr
What are the best, up-to-date books to learn Clojure for an experienced
developer pretty familiar with FP?

~~~
greenonion
Probably Joy of Clojure.

~~~
iLemming
Joy of Clojure arguably not very suited for beginners

------
mercer
For those of you who have experience with both Clojure and Elixir: what would
be reasons to choose Clojure over Elixir, if any? And vice versa?

------
miguelrochefort
Want to affect the way you think about programming?

Learn Prolog.

~~~
taktoa
Prolog is a programming language for turning polynomial-time algorithms into
exponential ones.

~~~
zmonx
And, true to form, it often works in the _other_ direction too!

Especially with CLP(FD) and other Prolog constraints.

------
bryanrasmussen
The problem is that I want to expand my brain, but I also want to get things
done and I have a family.

I think this is one of those you can choose 2 situations.

~~~
jasonkostempski
Use breaks and sleep less once in a while. It's just what you've got to do if
you want to learn new things outside of your current obligations.

------
agentultra
The _perfect_ language? I doubt that. It's probably quite decent.

~~~
grouchoboy
The perfect language to expand your brain. In a world dominated by java, php,
c++,... In my opinion yes, Clojure could the perfect language to continue
learning concepts, at same level would be Haskell.

~~~
yogthos
It's also very pragmatic, and probably most used functional languages in the
industry at this point.

~~~
keymone
wish that were true, but i doubt it. scala, prolog and erlang are all higher
on tiobe index.

~~~
yogthos
I personally don't view Scala as a FP language, it's a FP/OO hybrid. It's not
opinionated in that regard, and a lot of code in it is written in traditional
OO style or a mix of the two.

Erlang is another widely used functional language, but it's not very widely
used outside the telecom niche. Clojure has the advantage of running on the
JVM, and makes it easy to target a much wider range of domains.

~~~
lispm
Clojure is also a hybrid. The other part is called Java or Javascript. This is
claimed as an advantage, since there is already a lot of functionality in
another language to be reused by a direct interface. Some stuff is simply
deferred to the host language and since the other part is based on OOP,
applications will then be a mix of more FP-oriented code calling OOP-oriented
code.

~~~
yogthos
This is an implementation detail, and doesn't affect the API presented to the
user. For example, consider the clj-http library that's backed by the Apache
http Java library internally [https://github.com/dakrone/clj-
http](https://github.com/dakrone/clj-http) . As a user of clj-http, I don't
know or care about the fact that it's a wrapper around OOP code.

Furthermore, if you wanted to, you could reimplement the internals in Clojure
and the users of the library wouldn't be affected.

Being able to leverage existing mature libraries is a huge advantage, and the
fact that they can be used via idiomatic functional APIs provides the best of
both worlds experience.

~~~
lispm
The author of such a wrapper library writes this hybrid code.

Wrapper libraries are one way to deal with hybrid code.

~~~
yogthos
Sure, just like if you did FFI in CL. I'm not really sure what your point here
is.

------
davidreiss
That's true of any language. Even within the same language paradigm.

If you know C#/Java then learn C++ or vice versa and it'll affect the way you
think about programming.

Go outside of the statically typed OO world and try out the dynamically typed
OO languages like ruby or python.

Even better, learn a weakly typed procedural language like C ( lingua franca
for CS ).

Or choose an architecture and learn some assembly. Now that will affect the
way you think about programming.

Move out of onto a different domain altogether and try one of the flavors of a
declarative language like SQL.

Learning a bit here and there of many different languages and paradigms will
affect the way you think. Clojure isn't special.

You can even just stay within a framework and try to get a deep understanding
of .Net language/IL/Framework Libraries/Runtime stack. Then you get into the
debate of breadth vs depth. Should you learn one language/framework/paradigm
exceptionally well or should you learn a bit about a lot of a lot
languages/paradigms?

~~~
jasonkostempski
That is true. Heck, eating a particular meal might affect the way you think
about programming. But the article title, and the original HN title, is
"Clojure - the perfect language to expand your brain?" So it's asking if
Clojure is better at it than other languages/paradigms.

~~~
davidreiss
> So it's asking if Clojure is better at it than other languages/paradigms.

My argument was that there are such a wide variety of
languages/frameworks/paradigms that it makes no sense to make such a claim.

Someone from a functional background ( lets say you know scheme or ML ) would
get more from learning an OO language than from learning clojure. He'd learn
more from learning assembly and seeing how data moves in and out of registers
than from learning clojure.

Programming is such a wide topic. We get this posts all the time. Go will
expand your mind more than anything or ruby will or F# or any other flavor of
the day or even python.

It all depends on who you are and what you know.

In other words "Clojure - the perfect language to expand your brain?" is a
silly assertion. There is no "perfect language" because everyone's brains are
different because we all come with different backgrounds and expertise.

But that's just my opinion.

------
legendiriz68
" A language that doesn't affect the way you think about programming, is not
worth knowing."

If this would be common practise nobody would learn golang.

~~~
eliben
Golang certainly affected the way I think about programming, having learned it
after ~15 years of programming experience.

FWIW, I think most language can affect thinking - but the degree varies.

------
shadowmint
Our experiences with clojure are clearly different.

There have been plenty of people who have built successful businesses with
perl too. /shrug

I'm still going to recommend people not use either language, because I've
personally encountered the downsides of 'when things go wrong'; and it's been
significantly worse than in other languages.

> Are we doing opinion threads now? Okay. I can do one too!

That's a bit of a flip off isn't it?

What I have to say is based on my professional experience. Don't like it?
Tough. Luck. You had a different experience? fair enough. You want to call it
an opinion thread? Well, you know what they say. Opinions are like assholes,
everyone has one...

~~~
dang
Ai yai yai, you took this thread way into the red. Could you please resist the
temptation to do that in the future?

The whole idea of HN is to have thoughtful discussion (not to tell one another
to fuck off!) That means tolerating a certain amount of provocation when you
feel provoked; it's almost always unintentional, and in the rare cases when it
isn't, you owe the community better than to respond in kind.

We detached this subthread from
[https://news.ycombinator.com/item?id=14929745](https://news.ycombinator.com/item?id=14929745)
and marked it off-topic.

------
maehwasu
let clojure = Haskell

