Do you agree that the essence of Clojure in 2019 is to be a pragmatic data driven language?
If not, what is the most important aspect of Clojure: functional, LISP, interactive, dynamic … ?
Do you agree that the essence of Clojure in 2019 is to be a pragmatic data driven language?
That’s one way to put it. I do think the key differentiators for Clojure are:
- A Lisp
- With strong support for concurrency and parallelization
- Hosted on existing platforms
- Where data is modeled using nested heterogeneous immutable data-structures
- And code is data
- Which means data can drive both state and functionality
- That is mature, stable, and performant enough to be used for real world applications in a wide array of domains: backend services and servers, front end web development, full desktop applications, command line applications, big data processing pipelines, etc.
That probably qualifies as making it a pragmatic data-driven language.
I think being a Lisp already implies that it will have good support for functional programming, interactive development, dynamic types, and macros + meta-programming. Though if you’re talking to someone who doesn’t know what a Lisp entails, you could list those out separately.
In my opinion, being a Lisp is already a differentiator in a sense, because of the functional, dynamic, interactive, homoiconic, meta, and structurally manipulatable features they entail. But the other bullet points in my list above differentiate Clojure from other Lisps as well, which makes Clojure a unique beast.
This combination of traits I just listed, I can’t think of any other language which has them. Elixir might be the closest I can think of.
That’s how I’ve been pitching Clojure recently. Someone asked why not Haskell? recently on a reddit post. I think my best answer was, because Clojure is best at what it tries to be. If you look at that list I just gave, it’ll be hard to find a language that better realizes these traits. In that way, Clojure is the best Clojure. That’s not true of Haskell. You can easily point out other languages that compete with Haskell’s proposition like Rust, OCaml, Agda, Idris, F#, and it is not obvious that any one of them truly trumps the others. They make different trade offs. But Clojure either trumps, or simply lacks any competition. So at least when you go with Clojure, you know you’re getting the best at those things that there currently is.
I agree Clojure is a pragmatic data driven language.
My programming philosophy is The Pure Function Pipeline Data Flow
The Pure Function Pipeline Data Flow, based on the philosophy of
the Great Unification Theory, In the computer field, for the first time, it was realized that the unification of hardware engineering and software engineering on the logical model. It has been extended from
Lisp language-level code and data unification to
system engineering-level software and hardware unification. Whether it is the appearance of the code or the runtime mechanism, it is highly consistent with the integrated circuit system. It has also been widely unified with other disciplines (such as management, large industrial assembly lines, water conservancy projects, power engineering, etc.). It’s also very simple and clear, and the support for concurrency, parallelism, and distribution is simple and natural.
There are only five basic components:
Pipeline (pure function)
Reflow (feedback, whirlpool, recursion)
Shunt (concurrent, parallel)
The whole system consists of five basic components. It perfectly achieves unity and simplicity. It must be the ultimate programming methodology.
This method has been applied to 100,000 lines of code-level pure Clojure project, which can prove the practicability of this method.
The focus on being data driven is what separates Clojure from most other languages in my opinion. The idea of using data to describe APIs is very popular in Clojure community, and it affords a lot of benefits. It makes it much easier to reason about how the APIs work, it makes it trivial to compose different libraries together, and it allows serializing things without any additional effort.
Another big aspects that are worth noting are consistency and simplicity. You can be productive in Clojure by learning a small number of concepts, and most code in the wild tends to follow a common set of patterns.
I do not agree.
Pragmatic is ambiguous. It can be interpreted in too many ways, in too many contexts. So I can’t put it in the “essence” category.
Data-driven also has two common interpretations, and I’m not sure which one you are using. It sounds like you’re conflating these terms:
- Data-oriented, meaning you represent entities and their relationships as data.
- Data-driven, meaning you create DSLs in data structures and write interpreters for them.
I have a feeling you mean #1.
I guess I have two answers.
The essence of Clojure:
- General purpose language
- Hosted (use whatever the host gives you, with good interop)
- Repl-driven development
- Data-oriented with immutable data structures (instead of custom data types)
- Concurrent by default
- Lisp (language extension through libraries)
- Dynamically typed
- Functional programming
The selling points of Lisp, though, are different. “General purpose language” is very common, so it’s not a good selling point.
The selling points:
- Repl-driven development - faster, happier devs
- Concurrent by default - easy to avoid heisenbugs
- Data-oriented - ecosystem of libraries easily work together on common data types
Interesting. To me, pragmatic sounded perfectly right. I’ve interpreted Rich’s The Language of the System as a call to being pragmatic over being pure. Where the platform doesn’t necessarily mean the JVM, but the data we’re processing. Our part in the system. If we don’t control everything, we might not want to create a bunch of classes where our own reality rules.
That’s a great breakdown. Would you still say Clojure is data-oriented and data-driven? Or just one of those two?
I wonder, is Integrant both data-oriented (you specify using a data structure the components and the relationships between them), and data-driven (this data structure affects the order in which your code is loaded)?
Regarding OP, I would agree that in 2019 the tendency has been to make the library ecosystem more data-driven.
A little addition. Just listening to your The REPL appearance, and I’m enjoying it a lot! Great perspective for introducing Clojure to others.
At the 24 minute mark, you talk about Clojure’s CSV parser; how it’s small, simple and just does the little thing you need. That’s just what I’m talking about! That’s really practical to me.
On the other hand, I see your point about practicality being subjective. And it might be hard to persuade Python programmers that Clojure is more practical than Python.
I feel pragmatic and practical aren’t the same thing exactly. In that I’d say practical means that it is useful for the day to day real world use cases. While I’d say pragmatic is more a design tenet, where if there is a design challenge, which is limiting the solution space, practical compromises will be made.
I think Clojure is very much pragmatic in that way. It is also practical, in that it has everything you’d need for most day to day real world use cases, such as a large set of libraries and frameworks. But it is also pragmatic in how for example its macro system is unhygienic, but gives you the tools to address 99% of the practical use cases. Or how its data-structures can be mutated if need be, for practical performance considerations. Or how functions can be impure. Or how exceptions can still be thrown. Etc.
You’ll often see people complaining about all of these. People ask how come there is no add to the end of a list? That’s a pragmatic choice not to allow a convenient slow O(n) insertion operation. Why does Clojure have exceptions instead of using a error return instead like Either, and that’s a pragmatic choice to keep exception handling compatible with Java’s. Etc.
Haskell for example I’d say is not a pragmatic language, but it is still practical, in that it can be used effectively to solve a lot of day to day real world use cases. That said, if a use case needed something simpler to work with, or which can not currently figure out a way to do it which keeps the theory intact, it won’t be done. In Clojure, a compromise would be put in place instead.
That’s my take on it at least.
I’d say as a language, it is data-oriented. But it does support a lot of data-driven programming. That’s an optional thing that you can bring to your software as a programmer. The two are certainly not mutually exclusive, but I don’t think Clojure goes any extra miles to be data-driven.
I agree with you that the term pragmatic isn’t exactly the same as practical in this context. Pragmatic is a design tenet that chooses practical compromises where necessary. Very true.
Pragmatic, as well as practical, is subjective because it’s dependent on a purpose. A Python programmer might say that Clojure’s use of immutable data structures by default is not practical, both from a perspective of foreign-ness (new idioms to them) and because the algorithms they are implementing are quire natural with mutable state. You could also make the argument that they are less performant, and so they are not practical.
We, as Clojure programmers, tend to say they are practical because you never know when you will want to make a sequential algorithm parallel. Also, you never have to worry about sharing data.
Both arguments are correct. It depends on what you value more as a default.
And I would argue that you could always find lines between any two sides where you could make good arguments on both sides. That’s why I think pragmatic, without qualifications, is devoid of meaning. Just like practical is devoid of meaning without something to be practical about.
You could say “Clojure is practical for concurrent programming” or “Clojure is practical for JVM programming (due to interop)”. But then you’re better off including the context as its essence, as per the original question. That is, “Clojure’s essence is concurrent programming” and “Clojure’s essence is JVM interop”.
In the end, I think pragmatic is not specific enough to touch at the essence of Clojure’s design philosophy. I think I know what you’re getting at by using the term, after years of working in Clojure, but it’s not a good way to explain to others. Other languages could also claim pragmatism and you can’t argue with them. If you want to get at the essence, you have to go more specific and more concrete.
That’s true, pragmatic is a bit of a weasel word.
From this discussion, I came over this: https://www.quora.com/Do-programming-languages-have-pragmatics
And the answers argue that languages have syntax-es, semantics as well as pragmatics. And the latter is very important, as well as the hardest to formalize.
I like that idea personally. Such things (and I pseudo-quote): how and why people use the language in a certain way, and what each feature is useful for.
I feel thinking of pragmatics that way is quite useful. And if I think of Clojure, I can see that the design of most features has had ample amount of thoughts happen related to this topic. Transducers weren’t added simply for syntactic or semantic reasons, or for research purpose, or for some theoretical parity. They were added for pragmatic reasons.
Now, in that sense, you could argue all languages are pragmatic. So we’re back to square one in that saying a language is pragmatic doesn’t say much. Since all languages have pragmatics, instead, you need to explain what those are, that is, what are the features given useful for, how they are meant to be used, and why it is they should be used.
I’ve also enjoyed the technical linguistic definition of “pragmatics” that I hadn’t come across before, but its use there (roughly the “purpose behind the meaning”) is definitely not the ubiquitous usage of pragmatic which is centred on design trade offs made to save time and effort in order to deliver. I think Clojure made a few absolutely conscious and important design trade offs, but never ever to save time and effort, and we continually reap the benefits of the extra time taken to design for simplicity and the extraordinary corpus of thought that was brought to bear on doing so - way more than I ever knew existed. Discovering these thoughts through Clojure has been my favourite part of learning the language
At my workplace I had a go at summarizing “what makes Clojure different” in an onboarding README as follows. From memory this list was mostly drawn from the clojure.org pages at the time.
Clojure is simple (but not easy):
- lisp - parenthesis, homoiconic, macros
- functional - immutable, values
- concurrent - atoms, epochal time model
- dynamic - interactive, repl
- data-driven - information, facts, open, growth, spec
- abstraction - protocols, multimethods, ‘expression problem’
My purpose here was to draw out that if you “get” the lispyness and functional bits - which are often the first bits everyone gets to grip with - there’s a lot more still to get! My favourite area to try and get folks to grapple with is using open information in Clojure maps (and even in the persisted layer if possible) vs closed information containers as the real “things” we model in the world.
well first of all i think everybody has already made really excellent points,…
therefore i am not sure if my 5 cents can add anything of value, or if i am even on topic,… so here goes nothing…
to me this question is fundamentally one about classification ( pretty much my favorite
subject matter these days :-)) and therefore all that can be said in general about classification is valid and relevant in this particular case as well.
( here is the link to a youtube video in which i elaborate on classification in greater detail: https://www.youtube.com/watch?v=cDNHIGMSMhQ )
to be more concrete, classification ( most often, and this case presents no exception ( i think )) establishes an artificial / synthetic structure for the purpose of constructing a ( seemingly ) rational argument around it. ( usually an argument that is in support of someones personal convictions / interests. )
also this kind of classification / discrimination, ( after all to classify and to discriminate are just two sides of one and the same medal ) it always and necessarily entails some degree of distortion and simplification.
alright, so when i then read for example:
But Clojure either trumps, or simply lacks any competition.
So at least when you go with Clojure, you know you’re getting the best at those things that there currently is.
to me this feels somewhat like the inevitable outcome of the argument, given the predisposition and bias of the author. ( and perhaps the real reason behind and for doing the classification in the first place :-))
in other words, my worry with this type of classification / argumentation is that, it sometimes appears, to some small part at least, like an attempt to rationalize and or justify personal convictions / believes in a self-serving manner.
( socrates was ugly, right?.. so that explains it then :-))
now look, don’t get me wrong, of course it makes sense to try to highlight those aspects which are most in favor of the argument that one is trying to deliver, every sales-person / politician, worth their salt, knows this full well,… but the crucial point is, i think, to still and always make an attempt to stay as aware as possible about what it is, one is doing, because otherwise one could at some point down the road, suddenly end up with a dangerously distorted impression of reality, which then leads one to draw deeply flawed and questionable conclusions.
( … isn’t our neighbor just such a miser?.. well you know, aunt betty told me the other day over tea and biscuits that one of his grandfathers was actually a scotsman… oh is that so?.. well then, there you have it :-))
now of course, this is just programming languages and paradigms and not race, gender, religion, nationality or anything commanding some real seriousness, and of course a good deal of many an endless editor war type debate, is of a fundamentally humorous nature,… ( as st. ignucius from the church of emacs preaches to all of us ),… i get that…
still, lately i feel i have matured somewhat and hence decided to switch strategy a bit… here is what i do:
when people ask me why i like emacs or lisp better than x or y, i offer the following question as my answer:
‘what do you prefer, lasagne or sushi?’ often times this then turns what i have very often perceived as very heated yet pointless discussions, ( in fact i used to get really worked up over this sort of thing,… :-)) into a friendly chatter about grandma’s superb roast pork recipe.
the retort’s point is of course quite simple: if i happen to just really ( REALLY! ) love sushi, or say, if i happen to run a sushi restaurant, well then this means that i have a vested interest in the promotion and continued flourishing of the famous japanese dish, and of course i will ( at least try to ) come up with all kinds of arguments that will ( hopefully ) help me triumph over those evil layers of béchamel sauce, ragù and pasta; ( DO NOT FORGET ABOUT THE PECORINO ON TOP! it really does make all the difference in the world :-))… and to do so is totally legit, because i just want to share my passion about onigiri and company with the entire world, and also, it is just entirely frustrating to me, when people, ignorant as so many of them clearly are, ( ‘raw fish, seaweed and cold rice?’ she asked me with an expression of utmost bewilderment… can you believe that!!! ) simply do not seam to get the vast and obvious superiority of the far eastern delicacy ( of course enjoyed with just the right amount of wasabi and soy souce ), over some boring italian noodle dish that’s first and foremost intended for consumption by overweight cats!
… wow… i really did not think i would end up writing this much… also, doing a food metaphor made me really hungry, plus… i am afraid i have kind of forgotten what my point was to begin with…
…hmmm… well let me see… right!.. what i was trying to get at is that eclipse sucks! also clojure rules!!!..
great, now i’ll order some chicken masala,… and be a happy camper… cheers!
Very insightful. I too actually am quite fond of recognizing that taxonomies serve a purpose, and are really artificial construct. Most semantic debate don’t go anywhere unless purpose is defined.
I like to tell people about Tomatoes. Is it a fruit or a vegetable? People debate it for hours.
The truth is, a Tomato is a Tomato. Fruits and Vegetables are models that we have made up, abstract categorization, yes like you say, simplifications almost always of the real concrete world. These categorizations are abstract models we made for a purpose. Programming is almost the science of this process of abstracting and modeling real concrete things using computers for x, y purposes.
If you want to cook, it will be a more useful mental model to think of a Tomato as a vegetable. If you’re out of a fruit for a given recipe, please don’t substitute it for a Tomato. Nobody wants Tomatoes in their fruit cake, or Tomatoes in their fruit punch.
Botanically though, tomatoes have seeds, and are used by plants to reproduce, and that’s the class of vegetables that botanist decided on. If you need to grow another tomato plant, it’s quite useful to think of the tomato as a vegetable.
My purpose was fully to entice others to try Clojure. I think this whole thread is about coming up with an honest sales pitch.
Now, I wanted to add something to that though. Not sure how to best word it.
While you can say that classifications can be taken for the purpose of framing a certain argument to convince someone, and that’s definitely a part of my strategy here, as I try and entice people to try Clojure. Good classifications are also useful tools to reason and arrive at better than random predictions and decisions.
As long as you have that awareness like you said, of understanding where the model begins and ends, that the model isn’t the real thing, and that models have limits and can show bias, etc.
So say I reframe the question. I am someone looking to choose a new programming language to learn and use for my next project. I make an assumption that programming language choice matters to the success of my project, and to my enjoyment of working on it. That assumption means I shouldn’t go about randomly picking a language, or just sticking with what I know just because I already know it. So how can I make a better than random prediction in this scenario? What means do I have to make a reasoned choice here? Not a random one, which hopefully turns out more accurate than random.
Most likely, you’ll need to start building a model here, which probably will include categorization, classification, taxonomies, etc., as those are good tools for modeling.
With that, I think I’ve been providing a classification of Clojure in good faith. If you do choose Clojure, you should definitly not be surprised about how I had classified it. In that you should be able to reverse engineer why I did so, and see that it wasn’t all lies or gigantic mental leaps and stretches, that I didn’t leave huge gap, or provided only a tiny frame, etc. That’s my good faith. It also aligns with my incentives, in that I don’t just want you to try Clojure and then realize you’ve been duped, and leave. My purpose is for people to try it, like it, and continue to use it.
So, you can look at my list classification as, if you are looking for these things, and think they are key to your next project’s success and enjoyment of working on it, Clojure fits pretty damn well. From me trying to fit other languages I know in this model, Clojure fits the best.
Back to pasta… If someone wants protein and no carb, It’s pretty honest to say Sushi (the raw cuts of only fish) is a better fit then pasta.
With my why not Haskell, I’m appealing to people’s desire to have the best at things. And it’s a different model I’m pushing. To bring pasta back. Is Lasagna or Sushi better? Well, they have different characteristics, but assuming you decided either set of characteristics would work for you. Well then, you should really have my Moms Pasta over Miyagi’s sushi. That’s because my Moms Pasta is the best pasta around, of all the pasta, it’s the most tasteful. While Miyagi’s sushi is good, but there’s plenty of good sushi place to go by. This is also a good faith argument in the sense of the person asking me for my own opinion. I do truly think my mom’s Pasta is the best pasta I had. While Miyagi’s sushi is an alright sushi which compares pretty evenly to other sushi places. So if you were looking to try the current best in one of those, and you trust my opinion, this can be a good way to decide as well.
Eh, my reply got pretty long as well, don’t worry about length, I found the whole thing very fascinating.
i did already give you a like for your post, but now i feel that’s just not nearly enough! not only did you get exactly what i was trying to point out, but you took it and build from it something much better!!! really really cool! thank you.
The first time I had a look at Clojure (2014), I didn’t get it. My impression of it was “this is functional”, but I didn’t grasp any of the other concepts. In the end, my impression was that Clojure was an inferior Haskell.
The second time around (2016-2017), I stuck to my guns a little longer. In part because I had decided to learn Emacs, I think, so this time around I stumbled into using the REPL in a right way. Early on, I watched some of Rich’s videos, which I found intriguing. But as I progressed, those videos got new meaning. That was the case with “The language of the system” and “spec-ulation”.
I found your approach to complex Boolean statements particularly interesting.
Are you using core async for your current projects?
I haven’t used core.async because it’s too complicated, I only consider using core.async when absolutely necessary.
My programming approach is a fusion of “functional programming” and “enterprise management”. It has an added benefit，It is very helpful for the communication between the information technology department and the management of the company.