Why don’t you start by introducting yourself so we can all get to know you? Or head over to the watercooler and strike up a conversation. We would love to hear from you!

If you’re not sure what to say then here are some ideas for your first post.

To make sure things stay friendly we have a Code of Conduct. By participating here you agree to abide by it, so please go and read it first. It’s not that long, and contains important information about how you are expected to behave around here. More helpful advice can be found in the FAQ.

Enjoy your stay!

:rainbow::blush::sunny::100:

Why Clojure over Python?

Community CenterWatercooler

Mar 2019

1 / 69

Mar 2019

Apr '20

Webdev_Tory

Mar '19

I would like some cogent discussion on the following question that I am faced with regularly:

Python has many advantages; why use Clojure?

Python advantages (the ones most often facing me)

- Familiarity: used by many colleagues and in the community (academic + datascience)

- Ecosystem: well-established libraries like nltk and scipy

- Relative easiness: a language emphasizing readability

Clojure advantages

- Functional (writing & expressivity advantage)

- Performance (handles multi-threading better, JVM beats non-C Python)

- Not often relevant in this field, though

- spec generative testing – useful

- Lisp (structural editing, full REPL)

- Ecosystem: Java + Javascript at your disposal

What would you add as selling points of Clojure in this debate?

- created

Mar '19

- last reply

Apr '20

- 119

- replies

- 19.2k

- views

- 34

- users

- 303

- likes

- 23

- links

Frequent Posters

16

15

14

6

6

6

6

5

5

3

3

3

3

2

2

2

2

2

2

2

2

Popular Links

82

YouTube youtube.com

43

GitHub - techascent/tech.ml: Base library for the techascent ml suite github.com

37

Rubber Ducking: My observations from evangelizing Clojure at work for the last year. rubberducking.com

34

data.csv/csv.clj at master · clojure/data.csv · GitHub github.com

30

https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/svm/base.py

You're viewing a summary of this topic: the most interesting posts as determined by the community.

Show All Posts

VIEW 1 HIDDEN REPLY

mvarela

Mar '19

This is not a very technical argument, but for me, programming in Python feels like programming with a straightjacket on. For the same “kind” of language, I’d rather use Ruby.

Otherwise, I think once the lispy-ness clicks, and if you’ve done functional programming in the past, then Clojure just is a better fit (at least for my mental model of computation).

VIEW 3 HIDDEN REPLIES

HolyJak

Mar '19

For me the main selling point (aside of the thought-through design of the language) is interactive development, with REPL connected to the live, running app and developing it while it is running, getting immediate feedback. Even if your app restarts quickly upon code change, you likely loose state, so it doesn’t give you the same interactivity as Clojure REPL.

didibus

Phill

Mar '19

So, let’s see what can even differentiate two language which are both Turing complete?

- Performance

- Scalability

- Memory use

- Correctness

- Speed of delivery

- Speed of change

- Supported platforms

- Fun

Now let’s compare against Python:

- Clojure is more performant, but will start slower.

- Clojure will scale quite a lot more, both in cores on a single machine, or distributed.

- I’m not sure, but I think Python might actually better utilise memory. Though I might be wrong, I’ll say this is a tie possibly.

- I would argue Clojure tends to more correct code, due to tbe nature of FP, immutability and the REPL. But this is debatable and hard to demonstrate one way or another.

- I think both Python and Clojure are quite productive languages, with lots of existing high quality libraries, so I’ll say this is a tie.

- I’d argue Clojure code bases are quicker to evolve and change over time, again, mostly due to the nature of FP, immutability, the REPL, and the strong emphasis on simple designs. That said, this is also hard to demonstrate, so let’s call it a tie.

- I think Clojure maybe wins in supported platforms, because it can run in the browser as well with ClojureScript. But, that’s also arguable, so let’s make it a tie, since Python runs on quite a lot as well.

- Well, Clojure is just way more fun than Python. I mean, is there any language more fun to work with than Clojure?

There we go, Clojure beats or ties with Python on all aspects, so I guess… It’s overall a better Turing complete language.

- Beginning FP knowing OOP and more6

Yogthos

Mar '19

I think that Clojure provides a number of advantages both in terms of language design and ecosystem, especially in the domain of services and web applications.

In terms of ecosystem I would say that having Clojure and ClojureScript is a clear advantage. You can use the same language on both the server and the client. You get shared code, shared tooling, and shared data structures. All the devs on the team are now also able to work with the entire code base, and you can easily move logic between frontend and backend.

Since Clojure doesn’t have popular server-side frameworks, it’s a common pattern to manage the UI with client-side frameworks like re-frame and implement the server side as a stateless service. On the other hand, Python frameworks tend to be focused more around server-side rendering. Treating the server as a stateless API makes it easier to add other clients such as mobile apps, and to scale horizontally.

Another piece of tooling that makes Clojure development more productive is the editor integrated REPL. Any code you write, you evaluate in the REPL straight from the editor. The REPL has the full application state, so you have access to things like database connections, queues, etc. You can even connect to the REPL in production. So, say you’re writing a function to get some data from the database, write the code, run it to see exactly the shape of the data it produces. Then you might write a function to transform it, and so on. At each step you know exactly what your data is and what the code is doing.

Having a live development environment makes natural to do exploration. If you’re solving a problem and you don’t know the best approach, it’s easy to experiment by running the code as you’re writing it. You can quickly try a few different approaches and settle on one that works best. This also affects refactoring, as you can immediately test what you did. The REPL is also very helpful when you’re looking at new code you’re not familiar with. By running things as you read them you can confirm that you understand the code correctly.

I think that dependency management story in Clojure is much better. And packaging applications as uberjar results in a single artifact that only requires the JVM to be run. It’s basically like having all your apps running in containers for free.

Clojure also has a number of advantages as a language. I would say the main feature is defaulting to immutability making it natural to structure applications using independent components. This indirectly helps with the problem of tracking types in large applications as well. You don’t need to track types across your entire application, and you’re able to do local reasoning within the scope of each component. Meanwhile, you make bigger components by composing smaller ones together, and you only need to know the types at the level of composition which is the public API for the components.

Next, immutability makes it possible to work with threads in a sane fashion. Clojure provides excellent parallelism and concurrency primitives out of the box. Python provides nothing comparable in this area.

Thanks to immutability Clojure APIs tend to be data driven. API functions take data as arguments, and return data as a result. You don’t have to worry about any hidden behaviors like you do with objects because data is inert.

This kind of isolation also tackles a lot of the same problems as microsevices. One of the main motivations behind microservices is to reduce coupling. With Clojure you can think of each namespace as its own microservice. You have a set of functions that you call, each function takes an input and produces an output. So you have similar benefits during development time, but you don’t have to pay the cost of a orchestrating many services in production.

I recently saw a Cognitect presentation where they used Pedestal as an example application. One slide shows that over 90% of the code is pure. All the state and IO accounts for less than 10% of the application. This is a completely normal situation in Clojure. [1]

Meta-programming in Clojure is strictly superior to what’s available in Python thanks to s-expressions. You can take any piece of code and transform it like you would any other data structure using the same language. Being able to treat code as data also means that you can serialize and load code for free.

Immutability and s-expressions combined lend themselves well to refactoring. You just select the expression you want to factor out, and pull it out into a function that takes the same arguments.

Finally, I think that s-expressions provide superior editor experience thanks to structural editing. When you’re manipulating Clojure code you’re thinking in terms of blocks of logic. When I use other languages I tend to think more in terms of lines of text.

[1] https://www.youtube.com/watch?v=0if71HOyVjY 82

1 Reply

- Server side as a stateless service vs server-side rendering and REPL help developing a project5

VIEW 1 HIDDEN REPLY

mars0i

3

Mar '19

Mentioned in passing above, but worth emphasizing: There are Java libraries for nearly everything. In many cases it’s utterly trivial to use them from Clojure. Even if you don’t use Java libraries often, when you need one and it’s available and it’s easy to use, that makes a big difference. Build tools (I use Leiningen, but I would guess that others are similar) make it very easy to use Java libraries–even ones available only as source.

Also mentioned above and worth emphasizing: fun. I discovered that on my own, and then found others mentioning it independently. One of the reasons Clojure is fun is the thoughtful design of many functions that makes it so convenient to use them together: What makes Clojure fun is what makes it more productive to code in Clojure. Also, a lot of the thoughtful design of functions is intimately tied to the FP-orientation of Clojure. So FP is part of the fun and productivity.

eccentric_j

Mar '19

I’ve been using Python professionally for about 6 years now. It’s a decent language and it’s cool seeing how it progresses with so many people behind it. That said I’m trying to move our Django app into smaller Clojure services somewhere between micro-services and a monolith.

With Python, and most OOP based languages, you are stuck having to describe each system in play and its relationship to other systems. This commonly happens with classes, and you’re going to end up with a lot of them. The problem is most of these classes you write often just end up wrapping a list or a dictionary. However, they are not compatible with any function or method that typically works on lists or dictionaries so you have to write more classes, more methods, and create more vocabulary to make two classes talk to each other. It’s also way too easy to over-engineer in Python. Often you’ll find discussions about what MIGHT happen, how a system MIGHT change, how people MIGHT use it. That is very difficult to know so you end up making your systems more complicated in preparation that they may have to do more later. Lastly, at the end of a project you end up with all this code that is only relevant to the specific framework or how one person thinks about the software. It’s unprincipled and decisions are often made by what makes the most sense at the time to whomever is writing it or what a team agreed upon.

In Clojure and functional programming you model most of your logic as pipelines receiving data and transforming it over time to a destination such as a database, server response, API request, etc… What feels very satisfying about this approach is you’re usually writing the most minimal, simplest code to accomplish those goals directly. You focus on solving the problem at hand with code best suited for that task. When you need more functionality you can build up complex functionality by combining smaller units of work. For instance if you have a function and you compose it with another function you get a new function that can do both those tasks.

Say for instance a web server. If using Django you have to work with Django’s Request and Response classes. You will spend a few hours studying the docs to get started, then you have to consult them every time you want to make a change because you have to use some method for setting a property on the request object.

In Clojure you can write a web server using a library like Ring. What’s great is that each request handler is a function that takes a request map and returns a response map. You rarely need to consult the docs once the general concept clicks. There are like 100s of Clojure core functions that operate on maps, changes are trivial to build up your request\response pipelines. You can easily plug in another person’s ring handler and since they are just functions as opposed to code written against some Django version’s Request class or View implementation.

Often you may hear that Clojure has very terse docs, that is true and there is room for improvement but at the same time it hasn’t been addressed because it isn’t as big of a problem as it might seem. In Python, you NEED docs, lots of docs to learn how anything works. Want to see how a Django view works under the hood? Good luck. Enjoy lots of side-effects, mutable state, and glue code to make all the classes involved talk to each other. Docs are absolutely required in languages like Python to get anything done. In Clojure, you can often just look at the source and find out the functionality is implemented in less than 20 lines of code. Typically it’s good practice to document what a function takes and what it returns which may not cover every nuance, but is usually enough to get started with it.

Functional programming is pretty universal. I had spent years learning Django, and felt that I definitely understood web development. However, as soon as I tried a different language I realized I barely had any idea what I was doing. All I had done was learned one tool, the concepts don’t translate to similar projects, each solution uses an entirely different vocabulary. Instead, functional programming is principled relying on pure functions, immutability, and reducing side effects. Whether you use F#, OCaml, ReasonML, Clojure, or Haskell those principles will still be in play. Transitioning is far easier because you’re mostly learning new syntax rather than a vocabulary to express problems within a specific domain.

2 Replies

mars0i

@eccentric_j, that is one of the best descriptions of advantages of dynamically typed FP (and Clojure in particular) over OOP that I have seen anywhere.

(I think that some of the points don’t necessarily apply to a statically typed language like OCaml/ReasonML, which has different costs and benefits. You get type safety, but not the same convenient flexibility. I like both approaches.)

linpengcheng

Most OO systems are just simulations of real-world surface phenomena, and the whole system, like a mess, I think it is not good method of OO to simulate the real world, but to design it correctly with an abstract refined data model as a prototype. For example, the ggplot2 of the R language, the system is clear, with the perfect data model as the prototype. So a good OO system is more inclined to a data flow system, and I think Ggplot2 is more likely to be a data-driven plot system if OO was not in vogue at the time.:slight_smile:

So I think Python’s OO approach will only encourage casual design, it is not suitable for the construction of large, serious, formal systems.

Few people adopt pure pipeline construction system, glad that you also like pipeline system, I am also, my pipeline method with "Pure function, pipeline, data flow, relational theory " as the pillar, the article is a bit long, you can see: The Pure Function Pipeline Data Flow

mars0i

Mar '19

@eccentric_j, that is one of the best descriptions of advantages of dynamically typed FP (and Clojure in particular) over OOP that I have seen anywhere.

(I think that some of the points don’t necessarily apply to a statically typed language like OCaml/ReasonML, which has different costs and benefits. You get type safety, but not the same convenient flexibility. I like both approaches.)

eccentric_j

Mar '19

Thanks @mars0i, with a bit of refinement and a more empathetic touch this could be my next article.

That said I’m very curious which aspects don’t apply to static typed languages. Could you please elaborate?

mars0i

1

Mar '19

eccentric_j:

That said I’m very curious which aspects don’t apply to static typed languages. Could you please elaborate?

Well, it could be that I was reading in more than you intended.

In Clojure and functional programming you model most of your logic as pipelines receiving data and transforming it over time to a destination such as a database, server response, API request, etc… What feels very satisfying about this approach is you’re usually writing the most minimal, simplest code to accomplish those goals directly. You focus on solving the problem at hand with code best suited for that task. When you need more functionality you can build up complex functionality by combining smaller units of work. For instance if you have a function and you compose it with another function you get a new function that can do both those tasks.

All of this could apply to OCaml (or ReasonML or F#), but what I was thinking was that often there would be a bit more work involved, because you have to get the types right. That’s where I think I might have been reading in more than you said.

In OCaml you can’t just pass an array to function that expects a collection and return a lazy list (which is unpopular and rare anyway) to another collection function, and you can’t just throw together defrecords and convert them into or from maps, and on top of that you can’t mix floats and ints in your arithmetic or in your sequences for that matter. And if you actually want some kind of map, you have to decide whether it’s a hash map or a some kind of tree or something else, and use completely different libraries for each, and then maybe jump through awkward hoops to specify the types of the elements in your map.

So a bit of care would be needed to build that pipeline in OCaml, and to me it seems like some of the upfront work that you described for Python would be needed in OCaml. I still suspect that OCaml is easier in that regard than Python–though probably harder in other ways. In addition once the OCaml program compiles, you know that you will never have a type error at run time; it just can’t happen, unless you are doing funny things like calling C. What I like, also, about OCaml, is that you can usually do all of the above without any type annotations (compare that with Java), because OCaml will figure it out–though a lot of OCaml programmers specify types for every function in a separate interface file.

If I was sounding down on OCaml, I’m not; it’s a great language, and type safety and efficiency are nice things. But it’s a very different experience, imo, from writing Clojure, which I love for different reasons.

(I would guess that Haskell programming is similar to what I described for OCaml, but I haven’t used Haskell in a very long time, and I never knew it well.)

(About the fact that you can’t mix ints and floats in OCaml, there is a project in development–“modular implicits”–that will allow you to mix them, and do other cool things, but as I understand it that’s a big project that might not be done for a while.)

2 Replies

didibus

Yup, with static types, you trade simplicity for correctness guarantees to varying degrees.

Your programs aren’t necessarily more correct, but at least you do know that they are correct in some ways, and to some people, that gives them the piece of mind they need.

eccentric_j

Thanks for explaining @mars0i

. I’m not as familiar with static FP languages as I am with dynamic ones, so it’s great to learn more about the differences :slight_smile:

VIEW 1 HIDDEN REPLY

Engelberg

Mar '19

In order from most to least important: Immutable data structures, improved performance, better concurrency, dialects for both client and server, more sophisticated repl.

My top gripe about Python: Python’s dictionaries only permit immutable data as keys (which is smart), but Python has very limited ways of constructing immutable data (which is incredibly constraining). This severely restricts the utility of dictionaries and the ability to nest data.

The main things I miss about Python:

1. Highly readable syntax

2. Great interop with some high-quality C-based numerics packages

Overall, though, I’m far more productive in Clojure. It’s especially superior for any use case that one might describe as “lightweight data modeling” requiring a “data-oriented language”.

VIEW 4 HIDDEN REPLIES

jwr

1

Mar '19

alex314159:

As someone who would like to use Clojure more often, it pains me to say it’s often hard to make the case.

In particular Python’s performance for most use cases is very good - if you use numpy you’re effectively doing computations in C. You can parallelize a lot of problems simply with the multiprocessing module. Worse, sometimes a naive Clojure implementation can be slower than pure Python.

Also compared to Python - the I/O part is still painful. Wes McKinney, the creator of pandas, himself said that a large part of the package’s popularity is the ease of use of the read_csv / to_csv functions. I’m sure that’s a barrier to entry in Clojure for many.

I think Clojure’s advantage is in live environments where you receive a lot of data asynchronously (tracking a production line, trading financial markets) - the multithreading abilities and the safety of immutable data structures then shines.

You are making some good points and I had to quote your entire post, because I will be following along now:

First, indeed the performance of highly-optimized matrix libraries is indeed excellent, and numpy provides a nice interface. That said, I fould that at least in the kinds of data analysis problems I encountered, nearly 80% of the effort was spent on pre-processing, cleaning up the data, extracting features, interactive analysis, and similar tasks. The actual computation took so little time (defined as a percentage of total client project wall clock time), that it really didn’t matter. That said, I did use direct interfaces to matrix libraries sometimes.

As to I/O: I agree it isn’t easy, although I find that these days a simple (drop 1 (csv/read-csv (io/reader (BOMInputStream. (io/input-stream filename)) :encoding "UTF-8"))))) gets me very far. Also, it produces a lazy sequence, which means you don’t try to hold all data in memory.

It’s interesting that you mentioned receiving data asynchronously. I had a BIG advantage when I worked as a data science consultant/freelancer. When I wrote a solution, I would start with data files from the client (logs, data dumps, etc). I would then build a solution using transducers and core.async (pipeline for quick&easy parallel processing). This would produce data for a visualization dashboard, written in ClojureScript and shipped as an Electron app.

So, what was the BIG advantage? Well, I shipped the app and told the client “now, if you’d like to give me a real-time feed of your data, in whatever form, the entire real-time data-processing pipeline is already there, so all you’re seeing could be turned into a production app/tool and updated in real-time”. That was a real eye-opener!

I think most discussions of “programming language X vs Y” are superficial, focusing mostly on syntax, “ease of starting”, available libraries. Not to mention the ridiculous timewaster discussions of “static vs dynamic typing” or “startup time”. The differences run deep and most advantages are small, but they make a huge difference when taken together, especially when you are on a schedule and a budget and need to ship real apps.

BTW, I mean no offense to the original poster, but — I am looking at the “comparison points” mentioned, and I think most of them are irrelevant from my point of view. I don’t care about “easiness” or “familiarity” (as Rich said: “instruments are made for people who can play them”), I don’t care that much about performance, I don’t do any generative testing. I care about building reliable and maintainable solutions on a schedule and a budget, and Clojure is just the right tool for that.

In my case, I use Clojure not because of any single advantage, but because of dozens of advantages. Transducers (very under-appreciated), core.async, tesser, lazy sequences, ClojureScript, EDN, spec, single data format for both server- and client-side, immutable data structures, sequence library — all of this plays together to create an environment which simply can’t be reproduced in Python.

1 Reply

didibus

I just parse <wtv>SVs myself now, using line seq. I found that to be much more reliable for some reason.

(with-open [rdr (reader "my/file.csv")]

(->> rdr

(line-seq)

(map #(split % #","))))

Where if the file has issues, I can just be smarter in the split and handle them however works for the given file. And after that I can also add my own field parsing if I need to convert anything from a string into something else.

Its pretty short and quick, and I feel it can easilly accommodate any kind of broken fileset I’d need.

didibus

Mar '19

I just parse <wtv>SVs myself now, using line seq. I found that to be much more reliable for some reason.

(with-open [rdr (reader "my/file.csv")]

(->> rdr

(line-seq)

(map #(split % #","))))

Where if the file has issues, I can just be smarter in the split and handle them however works for the given file. And after that I can also add my own field parsing if I need to convert anything from a string into something else.

Its pretty short and quick, and I feel it can easilly accommodate any kind of broken fileset I’d need.

jwr

Mar '19

I stopped trying to split the CSVs myself when I noticed that there are all kinds of corner cases — as an example, the code above will not handle quoted commas (inside quoted fields) correctly. I’d much rather use clojure.data.csv which gets most things right and lets me set the separator and the quote character.

The BOMInputStream (which comes from org.apache.commons.io.input) is another thing learned from years of dealing with CSV in the wild. Some files will contain a BOM (byte-order mark) at the beginning and you’ll need to handle that.

1 Reply

didibus

jwr:

I stopped trying to split the CSVs myself when I noticed that there are all kinds of corner cases — as an example, the code above will not handle quoted commas (inside quoted fields) correctly. I’d much rather use clojure.data.csv which gets most things right and lets me set the separator and the quote character

For me, its the opposite. I didn’t mean that my example was my new generic csv parser. I meant that, clojure.data.csv and others have always at one point failed me, because they all assume correct comma separated semantics. What when I have a file with two different type of escape characters? Or mix encodings? Or uneven columns? Or decimals that have currency characters in front? Etc. Sometimes there’s even missing newlines!

That’s where I found just doing it myself, I can very quickly and easily handle all corner cases specific to the file I’m parsing.

Clojure makes writing a custom parser super simple and quick.

Seriously, have you looked at data.csv’s implementation? https://github.com/clojure/data.csv/blob/master/src/main/clojure/clojure/data/csv.clj

It’s 146 line of code, half of which are comments, and half of that half is for writing csvs. So only 1/4 of that is for reading and parsing csv files.

How awesome is that!

linpengcheng

2

eccentric_j

Mar '19

Most OO systems are just simulations of real-world surface phenomena, and the whole system, like a mess, I think it is not good method of OO to simulate the real world, but to design it correctly with an abstract refined data model as a prototype. For example, the ggplot2 of the R language, the system is clear, with the perfect data model as the prototype. So a good OO system is more inclined to a data flow system, and I think Ggplot2 is more likely to be a data-driven plot system if OO was not in vogue at the time.:slight_smile:

So I think Python’s OO approach will only encourage casual design, it is not suitable for the construction of large, serious, formal systems.

Few people adopt pure pipeline construction system, glad that you also like pipeline system, I am also, my pipeline method with "Pure function, pipeline, data flow, relational theory " as the pillar, the article is a bit long, you can see: The Pure Function Pipeline Data Flow 29

2 Replies

mars0i

linpengcheng:

Most OO systems are just simulations of real-world surface phenomena, and the whole system, like a mess, I think it is not good method of OO to simulate the real world, but to design it

I’m not disagreeing about the remarks about Python. I want to point out OO was supposed to be a good way to model the world, but the world doesn’t only include properties that attach to individual things; it also includes relations that can depend on the things that are related. This means that in e.g. Java, people have had to do awkward things in which a method depends not just on the class its attached too, but also its arguments. (Some less popular object systems such as Common Lisp Object System don’t have this problem, and Clojure multimethods and protocols provide some similar functionality.)

eccentric_j

For me, programming is the process of designing a data model that is simple and fluent in manipulation. More than 80% functions of my project is ->> threading macro code block, each step is simple, verifiable, replaceable, testable, pluggable, extensible, and easy to implement multithreading. The Clojure threading macro provides language-level support for PurefunctionPipeline&Dataflow.

I completely agree! I feel like our job as engineers and developers is not to make complex tools to tackle complex problems but make complex problems more simple. If you can break down a problem into pure function pipelines, it’s a lot easier to debug, model in your head, discuss, and test as you mentioned in your article.

Your counter-point about OO also makes a lot of sense, I don’t think OOP is bad. I know it has value in certain contexts and when leveraged well it can be quite nice to work with. Ggplot2 seems like a great abstraction that doesn’t invent new vocabulary or API shapes and allows a lot of intuitive composability. It seems to follow a lot of functional programming conventions, providing light wrappers around common data types rather than anticipating users creating subclasses of these data types and reading a book’s worth of docs on all the different APIs. As you suggest though, this level of quality is more difficult to achieve in OO, where as it’s the path of least resistance in a functional programming focused language like Clojure.

mars0i

Mar '19

linpengcheng:

Most OO systems are just simulations of real-world surface phenomena, and the whole system, like a mess, I think it is not good method of OO to simulate the real world, but to design it

I’m not disagreeing about the remarks about Python. I want to point out OO was supposed to be a good way to model the world, but the world doesn’t only include properties that attach to individual things; it also includes relations that can depend on the things that are related. This means that in e.g. Java, people have had to do awkward things in which a method depends not just on the class its attached too, but also its arguments. (Some less popular object systems such as Common Lisp Object System don’t have this problem, and Clojure multimethods and protocols provide some similar functionality.)

linpengcheng

4

mars0i

Mar '19

I think it should be different people have different ways of thinking, so there is a preference for different methods.

The various design patterns for OO and FP are too complex and unnecessary for me, and I don’t want to see complex associations between objects, and I don’t want to use them.

Clojure Multimethods is just an elegant conditional branching statement, and I haven’t used a variety of OO features within the Clojure language, including protocols.

I tend to construct systems with the simplest concepts and the most basic techniques, syntax, and functions. Used to implement my mind, the line sequence structure of the pipeline is the simplest, each pipe pure function is independent, as long as the input and output in line with the series of data interface standards, you can connect to use, do not care about other things, If a bug occurs, like water pipe leakage is obvious, for me, this is the easiest way in the world, I just want to go straight from the starting point to the end. I Don’t want to use traditional OO and FP anymore.

There is a great poet Bai Juyi in China. even illiteracy understands and appreciates his poetry. I hope that my code can be understood by the junior programmer even in the most complicated system.

didibus

Mar '19

jwr:

I stopped trying to split the CSVs myself when I noticed that there are all kinds of corner cases — as an example, the code above will not handle quoted commas (inside quoted fields) correctly. I’d much rather use clojure.data.csv which gets most things right and lets me set the separator and the quote character

For me, its the opposite. I didn’t mean that my example was my new generic csv parser. I meant that, clojure.data.csv and others have always at one point failed me, because they all assume correct comma separated semantics. What when I have a file with two different type of escape characters? Or mix encodings? Or uneven columns? Or decimals that have currency characters in front? Etc. Sometimes there’s even missing newlines!

That’s where I found just doing it myself, I can very quickly and easily handle all corner cases specific to the file I’m parsing.

Clojure makes writing a custom parser super simple and quick.

Seriously, have you looked at data.csv’s implementation? https://github.com/clojure/data.csv/blob/master/src/main/clojure/clojure/data/csv.clj 34

It’s 146 line of code, half of which are comments, and half of that half is for writing csvs. So only 1/4 of that is for reading and parsing csv files.

How awesome is that!

1 Reply

madbonkey

Mar '19

The protocol is amazing too (if you‘re used to a 50+ nodes/5+ levels class/interface tree from Java or something):

(defprotocol Read-CSV-From

(read-csv-from [input sep quote]))

rodsenra

Mar '19

As expected in a Clojure channel, I’ve noticed the balance skew towards Clojure.

I think the question is too broad. In order to properly answer: Clojure or Python we need to restrict the context a bit more.

Factors that are relevant:

- what is the composition of your team? What is their background?

Python might be easier to teach. Clojure have better functional support.

- what problem are you solving? How much does it depend on an ecosystem of libraries?

Python was designed for easy embedding (like Lua) or re-using C libraries.

Clojure plays nicer in the JVM realm. Both have great support on the CLR/.NET

Python is a de facto standard for data science, Clojure is taking its first steps.

Clojure is better at leveraging multi-threading, Python is much more light weight.

- what is your deadline?

Clojure needs more craft. Python has a faster development cycle.

If you (the Team) master the tool (prog, language and its ecosystem) almost anything can be accomplished. I recommend always investigating the problem first.

Both languages are worth having in your tool box.

2 Replies

Webdev_Tory

rodsenra:

what is your deadline?

Clojure needs more craft. Python has a faster development cycle.

Your last point is curious to me; in what sense is the Python development cycle faster, given the REPL-driven development possible in Clojure?

didibus

PREFACE: I just want to preface this by saying, ultimately, there is no right answer. This is an opinion piece, an opinion with which I might change my mind on tomorrow. At the end of the day, the choice of language is based on whatever works for you, your team, and the business.

rodsenra:

what is the composition of your team? What is their background?

Python might be easier to teach.

I think you are making the: “Appeal to the lowest common denominator argument”. One that managers love.

You’re right off course. Short term, Python will allow you to hire cheaper talent quicker. But Python will never be your last language, unless your projects themselves are trivial. I think you will also eventually lose out good talent. The great coders won’t stick to Python very long, before yearning something more. Either they’ll wander off to typed languages, explore lower level raw languages, venture into Actor and other distributed models, or enamore themselves in the meta universe of Lisps, Prologs, etc. Or you need to give them really interesting projects.

Obviously, we’re making a people argument. So its not about the language, but about the people who uses the language.

So, assuming you only hire junior beginner programmers, you think Python will be most appropriate, and yield quick onboardings, and good yield. And I say that’s probably true in the short term.

What if you hired experienced senior devs? Or even intermediate devs? Maybe they already know 2 or 3 languages, or already moved beyond Python, they know C#, Java, Scala, C++, etc.

Or what when your junior devs have now been working on the team for 2 years?

I don’t have any data on this, and I’m not fully sure I’ve made up my mind. But I’ll make a proposition that choosing the path of least resistance will strangle a team and projects long term.

If you use a more interesting language, with more nuances, more power, more expressivity, which allows devs creativity and continuous learning opportunities. I think you will attract better talent, quickly find who in your team isn’t as good (and be able to find someone better to take their place), while also unlocking the full potential of your devs. And you’ll much more quickly end up in a dream team scenario, and the kind of mythical 10x teams that is so sought after.

If your projects don’t need such a team, and is more focused on quantity of output, this might not apply as much. In that case, you’ll probably be on a constant rotation from junior dev to junior dev. Which makes sense in such a scenario. Not everything needs seniority, or exceptional talent, or even people with full on CS degrees. If you’re putting Django websites together on contract, for various clients which run small mom and pop stores for example, that’s way different.

I’m walking a treacherous territory here I know. Don’t get me wrong, I’m not making any moral judgement of worth. I highly respect all individuals and their accomplishments and discipline. I wouldn’t be able to thrive and be successful making Django websites. It requires a different set of skills and motivations which I don’t have. And I admire people who are successful at it.

You might think I should get off my high horse (I should and I will in an instant :stuck_out_tongue_winking_eye: ). What I’m trying to say is: “Stop treating beginners, junior devs, and all devs in general like they can’t learn hard things and learn to ride a horse, even a really high one :yum:”. Instead, you should offer them a safe environment with the appropriate mentoring and support they need to be succesful, while continuously pushing and challenging them, and making sure they know it is okay to stumble and fail sometimes.

Also, you get better by doing hard things. If the argument is: “Use Python because its easy, quick and painless”. You should ask yourself: “How am I going to get better at computer science and software engineering?” “How am I going to maximize my teams growth potential quickly? If I make the decision not to challenge them?”

They say Clojure makes you a better programmer. Never heard people say that about Python. Wouldn’t you want to use a language that makes you a better programmer? Makes your teammates better programmers? Yes it’s harder, but nobody gets stronger by lifting small weights.

I’ll finish with some quote I don’t remember the source of and will butcher a bit: “Do you want to have 10 years of experience, or 10 years of experiencing the same thing?”

P.S.: There’s hyperbole a bit in my post, because my point is kind of subtle. I love Python, still use it sometimes for small scripts, or as a plugin language when embedded. And it can be a great stepping stone, especially to people new to programming.

P.S.2: I don’t think the Python interpreter compares to the Clojure REPL in any way. But that’s another debate I’ll keep for another time.

Webdev_Tory

Mar '19

rodsenra:

what is your deadline?

Clojure needs more craft. Python has a faster development cycle.

Your last point is curious to me; in what sense is the Python development cycle faster, given the REPL-driven development possible in Clojure?

2 Replies

rodsenra

Both languages are (or can be) REPL driven. Python was also inspired on Lisp and always had a REPL. Recently I had a change in my Team composition, and I had to port a Clojure API to a Python API just because there would be no time to train the team in functional programming and Clojure.

There was nothing wrong with the Clojure implementation, it was just about the poeple how had to maintain it.

I can give you a quick metaphor, comparing languages to weapons.

Clojure is like nunchucks (think Bruce Lee), elegant, powerful, versatile, but it takes longer to master, and while learning you can get hurt easily because it is not so easy in the beginning.

Python is like a rod or a bat, even a kid knows how to swing it, it is much friendlier in the beginning, if you never master it, you will probably be able to defend yourself with it with various degrees of elegance.

Both can be equally lethal and elegant in master’s hands.

rodsenra

Maybe you were concerned with more detailed aspects of what do I mean by faster.

Given that both languages have REPLs, interactivity is not an advantage when we compare Clojure against Python, so we need to look elsewhere.

I think Python (at least for the time being) provides a faster development cycle because:

- it has a more mature library ecosystem (you can find things in Java for Clojure, when there is no native Clojure counter part, but Python beats Clojure just because of longevity and community size).

Being a Lisp, Clojure should have the upper hand, but Lisp community is scattered, and Clojure is ~16 years younger than Python.

(Concrete example: try to find a native Clojure natural sorting library, this is my first Google result

https://medium.com/@wilkerlucio/natural-sorting-in-clojure-script-123749bf3ba)

- Better debugging (think stack traces) and tooling (I love Emacs and Cursive) for Python.

This is not just about longevity, but the glue to the JVM, the underlying multithreading and macros.

Do not help making debugging easier. At this, the very thing that makes Python “slower” (the GIL - Global Interpreter Lock that prevents leveraging multi-threading to the performance level of JVM), is the thing that makes it super easy to debug (in comparison to Clojure). And for true horizontal scalability, multi-processing support in Python defeats the limits on threading.

- Having “no macros” is also a huge benefit when it comes to debugging.

I could go deeper, but I think these arguments should suffice.

At the master level, the shortcomings cease to be blockers, because we avoid the pitfalls before they are created. And Clojure has advantages in terms of code composition, that can leverage productivity.

This is just my very humble opinion. Perhaps it just reflects that I need to learn more Clojure.

rodsenra

Webdev_Tory

Mar '19

Both languages are (or can be) REPL driven. Python was also inspired on Lisp and always had a REPL. Recently I had a change in my Team composition, and I had to port a Clojure API to a Python API just because there would be no time to train the team in functional programming and Clojure.

There was nothing wrong with the Clojure implementation, it was just about the poeple how had to maintain it.

I can give you a quick metaphor, comparing languages to weapons.

Clojure is like nunchucks (think Bruce Lee), elegant, powerful, versatile, but it takes longer to master, and while learning you can get hurt easily because it is not so easy in the beginning.

Python is like a rod or a bat, even a kid knows how to swing it, it is much friendlier in the beginning, if you never master it, you will probably be able to defend yourself with it with various degrees of elegance.

Both can be equally lethal and elegant in master’s hands.

rodsenra

Webdev_Tory

Mar '19

Maybe you were concerned with more detailed aspects of what do I mean by faster.

Given that both languages have REPLs, interactivity is not an advantage when we compare Clojure against Python, so we need to look elsewhere.

I think Python (at least for the time being) provides a faster development cycle because:

- it has a more mature library ecosystem (you can find things in Java for Clojure, when there is no native Clojure counter part, but Python beats Clojure just because of longevity and community size).

Being a Lisp, Clojure should have the upper hand, but Lisp community is scattered, and Clojure is ~16 years younger than Python.

(Concrete example: try to find a native Clojure natural sorting library, this is my first Google result

https://medium.com/@wilkerlucio/natural-sorting-in-clojure-script-123749bf3ba 7)

- Better debugging (think stack traces) and tooling (I love Emacs and Cursive) for Python.

This is not just about longevity, but the glue to the JVM, the underlying multithreading and macros.

Do not help making debugging easier. At this, the very thing that makes Python “slower” (the GIL - Global Interpreter Lock that prevents leveraging multi-threading to the performance level of JVM), is the thing that makes it super easy to debug (in comparison to Clojure). And for true horizontal scalability, multi-processing support in Python defeats the limits on threading.

- Having “no macros” is also a huge benefit when it comes to debugging.

I could go deeper, but I think these arguments should suffice.

At the master level, the shortcomings cease to be blockers, because we avoid the pitfalls before they are created. And Clojure has advantages in terms of code composition, that can leverage productivity.

This is just my very humble opinion. Perhaps it just reflects that I need to learn more Clojure.

didibus

5

rodsenra

Mar '19

PREFACE: I just want to preface this by saying, ultimately, there is no right answer. This is an opinion piece, an opinion with which I might change my mind on tomorrow. At the end of the day, the choice of language is based on whatever works for you, your team, and the business.

rodsenra:

what is the composition of your team? What is their background?

Python might be easier to teach.

I think you are making the: “Appeal to the lowest common denominator argument”. One that managers love.

You’re right off course. Short term, Python will allow you to hire cheaper talent quicker. But Python will never be your last language, unless your projects themselves are trivial. I think you will also eventually lose out good talent. The great coders won’t stick to Python very long, before yearning something more. Either they’ll wander off to typed languages, explore lower level raw languages, venture into Actor and other distributed models, or enamore themselves in the meta universe of Lisps, Prologs, etc. Or you need to give them really interesting projects.

Obviously, we’re making a people argument. So its not about the language, but about the people who uses the language.

So, assuming you only hire junior beginner programmers, you think Python will be most appropriate, and yield quick onboardings, and good yield. And I say that’s probably true in the short term.

What if you hired experienced senior devs? Or even intermediate devs? Maybe they already know 2 or 3 languages, or already moved beyond Python, they know C#, Java, Scala, C++, etc.

Or what when your junior devs have now been working on the team for 2 years?

I don’t have any data on this, and I’m not fully sure I’ve made up my mind. But I’ll make a proposition that choosing the path of least resistance will strangle a team and projects long term.

If you use a more interesting language, with more nuances, more power, more expressivity, which allows devs creativity and continuous learning opportunities. I think you will attract better talent, quickly find who in your team isn’t as good (and be able to find someone better to take their place), while also unlocking the full potential of your devs. And you’ll much more quickly end up in a dream team scenario, and the kind of mythical 10x teams that is so sought after.

If your projects don’t need such a team, and is more focused on quantity of output, this might not apply as much. In that case, you’ll probably be on a constant rotation from junior dev to junior dev. Which makes sense in such a scenario. Not everything needs seniority, or exceptional talent, or even people with full on CS degrees. If you’re putting Django websites together on contract, for various clients which run small mom and pop stores for example, that’s way different.

I’m walking a treacherous territory here I know. Don’t get me wrong, I’m not making any moral judgement of worth. I highly respect all individuals and their accomplishments and discipline. I wouldn’t be able to thrive and be successful making Django websites. It requires a different set of skills and motivations which I don’t have. And I admire people who are successful at it.

You might think I should get off my high horse (I should and I will in an instant :stuck_out_tongue_winking_eye: ). What I’m trying to say is: “Stop treating beginners, junior devs, and all devs in general like they can’t learn hard things and learn to ride a horse, even a really high one :yum:”. Instead, you should offer them a safe environment with the appropriate mentoring and support they need to be succesful, while continuously pushing and challenging them, and making sure they know it is okay to stumble and fail sometimes.

Also, you get better by doing hard things. If the argument is: “Use Python because its easy, quick and painless”. You should ask yourself: “How am I going to get better at computer science and software engineering?” “How am I going to maximize my teams growth potential quickly? If I make the decision not to challenge them?”

They say Clojure makes you a better programmer. Never heard people say that about Python. Wouldn’t you want to use a language that makes you a better programmer? Makes your teammates better programmers? Yes it’s harder, but nobody gets stronger by lifting small weights.

I’ll finish with some quote I don’t remember the source of and will butcher a bit: “Do you want to have 10 years of experience, or 10 years of experiencing the same thing?”

P.S.: There’s hyperbole a bit in my post, because my point is kind of subtle. I love Python, still use it sometimes for small scripts, or as a plugin language when embedded. And it can be a great stepping stone, especially to people new to programming.

P.S.2: I don’t think the Python interpreter compares to the Clojure REPL in any way. But that’s another debate I’ll keep for another time.

2 Replies

VIEW 5 HIDDEN REPLIES

didibus

Mar '19

Richard_Heller:

I feel one point that’s getting overlooked in this discussion is the turnover rate in today’s job market. Developers don’t stay long in one place, for one reason or another. Using a language like Python ensures the next wave coming in will be able to get up to speed and contribute quickly.

I think this is overblown personally. You can read my blog post here for details of my experience regarding this: https://www.rubberducking.com/2018/03/my-observations-from-evangelizing.html 37

Basically, my experience is that, learning the domain, the architecture, the tools, the libraries and the existing code base far outweighs learning the language. But, you need to offer good support of the language, so, without an existing expert available to do that, I can’t say if the result would be the same.

Also, the reason I stick to my team is partly because of Clojure. My team is an outlier using Clojure, and we are also an outlier in how long people stay, with a very low churn. Maybe that’s also because of Clojure, but I can’t speak for others, so I’m just speculating. It also has been a great recruiting tool.

So, I’m with you, I think companies and their managers share that opinion. Or at least, it is a source of perceived risk. And its possible it is justified. Not all niche language would necessarily end up not being a major overhead, or help to retain and attract talent.

But I think sometimes, it can actually be a differentiator to attract top talent, which might end up staying way longer because of their passion for the language. Can’t say for sure, so I don’t blame anyone who thinks its not worth the risk. For my team, it payed off though, that’s all I can say, small anecdotal sample.

teodorlu

Mar '19

Modules can’t be reloaded within the same session. After you imported it once, if you change something in the module, you won’t be able to see the changes reflected.

Agree with your point overall, but I’ve been experimenting with reload (Python 2) and importlib.reload (Python 3) trying to replicate a Clojure-like experience, and I’ve gotten some way. I don’t think it’s as good (I’m not sending expressions to the repl), but I’m managing to do hot reloading within the same repl. Hoping to share the workflow once I can get the code and API into a decent quality.

1 Reply

seancorfield

Can you connect an editor or command-line REPL client directly into a running Python application, possibly running on a remote server, and execute code against it? If you can’t do that, it’s a very different experience to the Clojure REPL, for better or worse.

seancorfield

Mar '19

Can you connect an editor or command-line REPL client directly into a running Python application, possibly running on a remote server, and execute code against it? If you can’t do that, it’s a very different experience to the Clojure REPL, for better or worse.

1 Reply

seancorfield

Mar '19

Richard_Heller:

you have a team of 20 developers

I can’t imagine needing a team of 20 developers for a Clojure project! I would expect a 20-person Python team could likely be replaced by a much smaller Clojure team and produce the same functionality with a fraction of the amount of code.

On the issue of macros making “Lisp look like whatever language you want” – it’s still going to look like Lisp because that’s the syntax. Macros just turn Lisp code into other Lisp code.

Now if you look at embedded DSLs in Scala, you really can create an alien-looking language that looks nothing like Scala code :slight_smile:

1 Reply

Yogthos

Another thing to note is that any large project can be broken down into smaller independent components. Small components are easier to reason about and maintain directly leading to higher code quality. It’s easier to onboard people to work with them, and you can reuse them for other projects. Smaller teams also have way less communication overhead because there’s less meetings, emails, and less need for coordination in general.

teodorlu

seancorfield

Mar '19

Nope, no editor integration. That’s why I use Clojure when I have the chance!

rodsenra

Mar '19

Thanks for the response Didier.

That really helped me to understand what you value on the Clojure REPL.

I would like to share the information that I have on those observations.

1. Indeed, Lisp is unbeatable on the S-expr approach. Totally agree.

2. About dependencies isolation, I beg to differ. Python do have namespaces (aka Modules) that are similar to Clojure Namespaces (both dynamic, both reloadable).Although the are different subtleties, I do not see you claim that Python does not support dependency isolation.

As for virtual-env, it is to isolate cross-project dependencies. They only enhance dependecy isolation, they do not break it.

I do not know how does Clojure handles cross-project dependency isolation.

3. I think Jupyter Notebooks are the best counter-example for the claim that Python does not have net-based repls. They are exactly that. And because Python was inspired on Lisp, it always had an eval mechanism, making as easy as in clojure to implement a net-based repl.

Mor info: https://stackoverflow.com/questions/15167200/how-do-i-embed-an-ipython-interpreter-into-an-application-running-in-an-ipython 5

4. The syntax choices of the languages are indeed different. And I prefer Clojure’s syntax over Python,

but the whitespaces given the proper IDE are a non-issue the same as parenthesis in Clojure.

Without a proper IDE or editing environment, I would advocate the Python syntax is more convenient

because there is no need for manual () matching.

5. Python have many immutable native datastructures (though not “persistent” as in Clojure). Those exist in Python but as libraries. And mutability is a resource that you can use to various degrees.

6. Again, syntax. We already agreed that Lisp’s have superior syntax.

7. Actually, Python modules are object that are created from files (just like in Clojure). So, yes, you can create a module dynamically at the REPL in Python. The semantics of namespaces is a bit different though, but namespaces nonetheless.

8. Modules can be reloaded. And, like in Clojure, you have to take precautions to be consistent on the consequences of reloading (after all that is why libraries such as mount and Components exist in Clojure world right).

9. I think you are misusing Python there. The semantics is the similar you create objects (vars) and the can have “symbols” that refer to these objects, and you can even inject those symbols into other modules (namespaces) that are loaded.

10. Methods can be redefined any time in Python, and they do not require the class to be re-defined. That was misinformation. There are ways to prevent that, but it is allowed by default for custom types.

11. There is ample support for reflection (and thus introspection) in Python. The thing is that “+” is not a function but a method. And help does work, you just need to give it the method object

help(1 .__add__). And again, help works very similar to Lisp. For any object (even created during the session), that has a docstring, help will show that docstring.

That is why I am saying, syntax aside, both languages have a lot in common.

Both inspired on Lisp (Clojure naturally more), both with a foot in the OO world (Python naturally more).

didibus:

1. Language is not expression based, which I found make things more clunky at the Interpreter, and force more code into a multi-line structure.

2. Dependencies are not isolated. You can use virtual-env, but then it requires a folder structure to first be created.

3. It doesn’t (didn’t ?) have network based interpreters and direct editor integration with them.

4. The whitespace matters syntax can be annoying at the interpreter, again, managing multi-lines gets tedious in those cases.

5. Reliance on mutability couples a lot of things to state, which gets trickier when doing heavy reloading and trying to maintain a working program state in your session.

6. Simple things, like having to put commas between elements in list and tuple literals, and colons in dictionaries. Oh, and between arguments to functions and in the parameters list.

7. Modules are tied to files. So in the interpreter, you can’t create modules, switch between them, etc.

8. Modules can’t be reloaded within the same session. After you imported it once, if you change something in the module, you won’t be able to see the changes reflected.

9. The whole declaring if your variable is global or local is confusing in an interactive session.

10. Methods cannot be re-defined, in that, the whole class has to be instead, and existing instances won’t get the new behavior.

11. Not everything is inspectable, for example: help(+) doesn’t work. And you can’t get the source of a function. Well, you can if it is defined in a file using the inspect module, but not for things defined in the session.

1 Reply

VIEW 33 HIDDEN REPLIES

seancorfield

Mar '19

Richard_Heller:

In Clojure, you have things like map, vector, reduce, thread macros, etc that are wrappers around code that does a bunch of looping, function calls, and data manipulation for you and you have no control over how they do it.

I can understand your frustration, but if you think that’s what Clojure is providing, you’re not “getting it” and still not thinking at the “correct” level of abstraction for Clojure to be productive for you. In a functional language, the abstractions like “sequence” and “collection” are fundamental – they essentially are the primitives, along with some “basic” operations on sequences and collections, namely “map”, “filter”, and “reduce” (and their variants) – and “composition” as a basic operation on functions themselves. Until those things are internalized as your new basis of thought, you’re going to struggle to read (and write) Clojure. Once you truly “grok” those, the issues you raise about readability will go away.

You said you understand Clojure’s concepts, but I don’t think you’ve internalized them yet as the (higher-level) primitives that the language provides: “I end up feeling like a mouse hammering away at a button trying to get the cheese to come out.”

That internalization is the “steep learning curve” and it’s particularly hard for folks who are steeped in OOP thinking, in my experience of watching people trying to learn Clojure over the last eight or nine years that I’ve been using it (in production).

[OOP] allows you to create self contained, reusable pieces of code that can be clicked together to solve more complex problems.

Well, that was its big promise when it came along – but the reality is that it has not delivered that. The level of reusability we got with C++/Java was nowhere near what was claimed we would get. That promise was why OOP went mainstream: it was a “silver bullet” for industry to dramatically reduce the amount of code that was needed and to allow businesses to “reuse” more of that smaller amount of code. OOP has allowed for “reuse in the small” but nearly all code is tightly coupled to business domain objects and is not actually reusable across the enterprise – and it’s also partly why so many large companies that bet on Java have such monstrous, unyieldingly monolithic codebases.

That concept is the founding cornerstone of OO philosophy, i.e. the data and functions/methods using and manipulating it are tied together into a self contained unit.

I see a closure (a founding cornerstone of FP philosophy, you might say). And it’s fairly easy to build OOP-like systems in most functional languages – and that was one of the exercises in the second Clojure workshop I attended back in 2010. It’s also what Brian Marick shows in his Functional Programming for Object-Oriented Programmers 3 book.

What we have in most OOP languages is a long way from what the originators of OOP intended – and not in a good way! :slight_smile:

1 Reply

Richard_Heller

seancorfield:

You said you understand Clojure’s concepts, but I don’t think you’ve internalized them yet

The concepts are simple. I fully grasp them. I have my sequences, maps, etc and my toolkit of stuff I can use to manipulate them. Got it. Then the rubber meets the road. I have my data, its currently at A, and I need to get it to B. How do I do that? Bam! Brick wall. I quickly find out the tools I’m familiar with are insufficient to do what I need to do. I say that confidently because every time I’ve gotten stuck and had to ask for help or look up a solution, the solution was never using things I was already familiar with. It was never a “Shoot, I should have known that!” thing. It’s always “OK, never heard of that. Good to know.” I wish I hadn’t realized it’s fundamentally IoC, though. I really, really dislike IoC. That could be part of the struggles, as well.

seancorfield:

Well, that was its big promise when it came along – but the reality is that it has not delivered that.

It actually has, but nothing is a silver bullet. The problem is they tried to use it for everything and nothing works for everything. UI programming, for example, is a great fit for it.

seancorfield:

What we have in most OOP languages is a long way from what the originators of OOP intended

Yeah, can’t argue that one. I would bet money, though, that if FP took off at the same level we’d be saying the same thing about it 15 years from now.

Richard_Heller

Mar '19

seancorfield:

You said you understand Clojure’s concepts, but I don’t think you’ve internalized them yet

The concepts are simple. I fully grasp them. I have my sequences, maps, etc and my toolkit of stuff I can use to manipulate them. Got it. Then the rubber meets the road. I have my data, its currently at A, and I need to get it to B. How do I do that? Bam! Brick wall. I quickly find out the tools I’m familiar with are insufficient to do what I need to do. I say that confidently because every time I’ve gotten stuck and had to ask for help or look up a solution, the solution was never using things I was already familiar with. It was never a “Shoot, I should have known that!” thing. It’s always “OK, never heard of that. Good to know.” I wish I hadn’t realized it’s fundamentally IoC, though. I really, really dislike IoC. That could be part of the struggles, as well.

seancorfield:

Well, that was its big promise when it came along – but the reality is that it has not delivered that.

It actually has, but nothing is a silver bullet. The problem is they tried to use it for everything and nothing works for everything. UI programming, for example, is a great fit for it.

seancorfield:

What we have in most OOP languages is a long way from what the originators of OOP intended

Yeah, can’t argue that one. I would bet money, though, that if FP took off at the same level we’d be saying the same thing about it 15 years from now.

2 Replies

huahaiy

Richard_Heller:

the solution was never using things I was already familiar with.

If that’s your expectation, you have made a mistake somewhere.

Functional programming is very different from OOP. If one is not willing to undergo a period of “I don’t know how to program any more”, it would be hard to overcome the obstacle that was created by the years of OOP experience.

I had gone through this myself about 7 years ago. I had been programming for 20 years by then, but with Clojure, I suddenly didn’t know how to program any more. Couldn’t do the simplest thing.

I did not try to justify my inability by going to a Clojure forum to talk down the language, instead I headed to 4clojure.com, and cut my teeth on those little exercises. Then one day, it clicked. The rest is history.

seancorfield

Richard_Heller:

It’s always “OK, never heard of that. Good to know.”

Can you give some concrete examples? (so many things can be built from reduce – including map and filter – so I’m having a hard time imagining that you “couldn’t” solve problems given a pretty small toolset that you say you fully grasp)

huahaiy

Mar '19

Richard_Heller:

the solution was never using things I was already familiar with.

If that’s your expectation, you have made a mistake somewhere.

Functional programming is very different from OOP. If one is not willing to undergo a period of “I don’t know how to program any more”, it would be hard to overcome the obstacle that was created by the years of OOP experience.

I had gone through this myself about 7 years ago. I had been programming for 20 years by then, but with Clojure, I suddenly didn’t know how to program any more. Couldn’t do the simplest thing.

I did not try to justify my inability by going to a Clojure forum to talk down the language, instead I headed to 4clojure.com 5, and cut my teeth on those little exercises. Then one day, it clicked. The rest is history.

1 Reply

mars0i

1

Mar '19

Richard_Heller:

linpengcheng:

I don’t understand why programmers like the OO method

Because of what you mentioned, Legos. It allows you to create self contained, reusable pieces of code that can be clicked together to solve more complex problems.

Take this code, for example, which seems to be fairly common in Reagent

(defn some-thing []

(let [state (atom {})]

(do-something state)))

That creates some data that is created when the function is called and is tied to the function that created it. That concept is the founding cornerstone of OO philosophy, i.e. the data and functions/methods using and manipulating it are tied together into a self contained unit.

Fun fact: The Scheme language (a functional-ish lisp) was originally intended by its authors Guy L. Steele and Gerald Sussman as a tool for exploring object-oriented ideas during the prehistory of OO. I am not sure how they went about that, but the idea that closures can be used to implement data encapsulation in objects (that’s essentially what the code above does) has been around for a long time. With a little bit of work one can add inheritance through delegation.

Richard_Heller:

In Clojure, you have things like map, vector, reduce, thread macros, etc that are wrappers around code that does a bunch of looping, function calls, and data manipulation for you and you have no control over how they do it.

If you prefer, you can iterate over the data using loop/recur. You miss out on some brevity and convenience, but in the end it should be a matter of personal preference. (I admit that that won’t help you understand others’ code, though.)

I know that the map function concept is unfamiliar to many people, but maybe it’s not that mysterious once you get used to the syntax. It’s just a little bit higher-level and less flexible than a for loop, or loop/recur in Clojure. It’s not a Clojure thing, either, except for the lazy output. It comes from Common Lisp and Scheme, which also inspired related functions in other languages. I used to use a map in Perl, for example (though I admit I had to worry about whether coworkers would understand the code). There is apparently even an analogue in Python 4.

fwiw, I almost never use thread macros. I guess I’m unusual, and I’m not a full-time Clojure person, but I’m usually happy with a chain of function calls or sequential let bindings, rather than having to think about the hidden arguments that are either passing through a thread macro chain as the first argument, or as the last argument, or that have to be jiggered into some other argument along the way.

Richard_Heller

Mar '19

huahaiy:

If that’s your expectation, you have made a mistake somewhere.

I didn’t expect that. My point was that the problem wasn’t that I already had the tools to solve the problems and just wasn’t using them right. I hit walls because I don’t have enough tools to solve the problems. In other languages, the first tools you learn are enough to solve a much wider range of problems.

huahaiy:

with Clojure, I suddenly didn’t know how to program any more

That’s my point. This whole thing started with people trying to claim Clojure is as easy to learn as any other language, which is empirically false. There may be various reasons for that, but it’s not an easy language to learn.

huahaiy:

I did not try to justify my inability by going to a Clojure forum to talk down the language

I’m not talking it down, I’m pointing out that it’s not as easy to learn as everybody wants to claim it is. It’s not a perfect, holy grail of languages. It has its perks. I’m learning it for a reason. I have my reasons. That doesn’t mean everybody will share my reasons and it doesn’t mean choosing a different language or paradigm is any better or worse. OOP is a perfectly valid and useful paradigm if used correctly. So is FP. It’s a matter of personal preference. Claims that Clojure is empirically superior in all these different ways simply doesn’t hold up. That’s not talking down the language. That’s reality.

huahaiy:

I headed to 4clojure.com, and cut my teeth on those little exercises.

I headed to Hackerrank for that. Been through that already. I know the language enough to solve basic CS stuff. I’m now trying to port my personal projects over.

1 Reply

mars0i

1

Mar '19

Richard_Heller:

[Which brings me to the epiphany I had last night while I was once again beating my head against the wall trying to get a web page written that should have been 30 minutes of work but instead is still incomplete after 4 days. When you read about peoples experiences learning Clojure, why do the terms “steep learning curve” and “frustration” keep coming up? Why don’t those same things come up with JS, Ruby, Go, etc?

Is this due to Clojure, or just any FP, or maybe just Lispiness? I did not feel a steep curve, but I had been doing a lot in Common Lisp recently (with a lot of imperative code), and had used Scheme, Standard ML, and a tiny bit of Haskell years earlier. Maybe one should expect a steep learning curve coming from those languages. (Well, I did get bit by laziness repeatedly, and I had a lot of trouble, at first, learning the right way to organize files for Leiningen and the JVM, and JVM stackdumps are not very friendly.)

I would never suggest that any functional language would be easy at first for people primarily used to OO and imperative programming. I think I’ve come across people who seem to pick up Clojure or OCaml quickly starting from OO, but I would not have assumed that’s the norm. So if that’s what people are saying–that Clojure is easy–I won’t disagree, but I don’t really know.

linpengcheng

3

Mar '19

I say Clojure is easy, probably because I mainly use Foxpro Desktop database programming before using Clojure, and I’m used to programming based on data sets. In FoxPro, programming using dataset commands is simple, clear, short, and high-performance.

So I had used VB, C# programming, I had Learned also C + +, Delphi, Java, Python, asm, etc. Their grammar, implementation mechanism, programming ideas are too complex, the code is too verbose. I’ve always thought they’re very difficult to use.

So, about 2011 years, as soon as I saw a Clojure Chinese introduction article, I like it, although my English level is not good, Clojure’s documents and books are very few, there is no Chinese documents, I still use Clojure in my project.

For me, Clojure is a super Foxpro.

Clojure able to fully express my thoughts, so that my programming ability has been greatly improved, and let me focus on problem solving rather than programming language.

Clojure is a functional programming language based on relational database theory 4

:smile:

seancorfield

Mar '19

Richard_Heller:

It’s always “OK, never heard of that. Good to know.”

Can you give some concrete examples? (so many things can be built from reduce – including map and filter – so I’m having a hard time imagining that you “couldn’t” solve problems given a pretty small toolset that you say you fully grasp)

1 Reply

huahaiy

1

Richard_Heller

Mar '19

I have not used Hackerrank, so I cannot comment on that.

The most useful feature of 4clojure is that you get to see other people’s solutions after you solve a problem, and you can also follow people. Following a few known good Clojure programmers, one would know the majority of the useful functions and idioms. At that point, I can hardly imagine how one would “hit a wall” using Clojure to solve problems after he has gone through a period of rigorous exercise like this.

There are less than 100 core functions that one needs to know by heart in order to become a Clojure master. Most of the functions match a specific conceptual “shape” of the problem and the name of the function is often very suggestive. E.g. map is a transformation from seq to seq; iterate is applying the same function on result and keep going forever; and so on. Intuitions like these are what one obtains through exercises. One cannot claim to have grasped the concept of Clojure without being able to immediately conjure up an appropriate function upon hearing the problem description.

mvarela

seancorfield

Mar '19

I think @Richard_Heller doesn’t want to be convinced about the benefits of Clojure over Python. If you have a strong Python background, it’s normal to find Clojure harder to grasp. I came to Clojure after having done some Haskell, so the functional aspects were not a big stumbling block, like they seem to be for him.

If you’re starting from a blank slate, though, I don’t really know that Python would be any easier to learn. There’s a bunch of OO-related knowledge that needs to be grasped, and that usually just piles on top of the inherent complexity of the problem one is trying to solve.

Both Lisps and FP take a while to “click” for people with an imperative/OO background. You need to “unlearn” a bunch of stuff (some of which are actual anti-patterns), and start thinking in terms of data being transformed.

@Richard_Heller, if you haven’t already, you might want to have a look at Graham Hutton’s paper on the universality and expressiveness of fold, to better understand how to see things in a more FP manner. (http://www.cs.nott.ac.uk/~pszgmh/fold.pdf 5 )

Richard_Heller

Mar '19

mvarela:

I think @Richard_Heller doesn’t want to be convinced about the benefits of Clojure over Python

Not true. I don’t use Python, I don’t really like it as a language. For ease of understanding and learning, though, it’s tough to beat.

mvarela:

If you’re starting from a blank slate, though, I don’t really know that Python would be any easier to learn

The empirical data says otherwise. If too much OO knowledge is the problem, then beginners and non-programmers shouldn’t have a problem. When was the last time you heard a non-programmer say they started using Clojure because it was so intuitive and easy to use? Or a non-programmer who needed to throw together a program to test a theory using Clojure because it just made sense and took no time to learn? Those are the reasons people turn to Python. I’ve never heard anybody say those about Clojure. Steep learning curve? Frustrating? Those things come up all the time with Clojure.

So, the question then became why? Why does it take so long to get over the hump? I now believe it’s due to a lack of primitives and the IoC nature of it. Map is not a primitive. It loops, calls functions, and modifies data. 3 different things. And you have no control over it, you set it up and hand it off to the Clojure runtime. When starting out, that makes it harder to figure out why things went wrong. Yes, you have to figure that stuff out in order to really use Clojure. I believe that’s why it takes longer and is confusing when starting out.

Then the questions about why would somebody switch to Clojure over another language? What would that brochure look like? There’s not really anything outside of personal preference. That’s just the way it is. The REPL? People just hear “hot loading debugger.” The feedback loop for iterative development isn’t a pain point at all, let alone enough of one to justify switching languages. OOP vs FP? That’s personal preference. A lot of people prefer OOP. For Clojure to gain wider use, it needs to solve better problems. As is, it’s no different than talking about Rust, Haskell, Go, etc. Another general purpose language that some people prefer using. That’s not a bad thing. That’s just the way it is.

I’m not trying to knock the language. If this was a Python forum and the gurus were trying to say that Python code was comparable to C code for performance or something, I’d call bs on that, too.

2 Replies

huahaiy

1

Mar '19

Reducing the preference of many experienced programmers for functional programming into a mere personal preference does count as talking down the language.

For it basically dismisses out of hand any technical arguments these people make on behalf of Clojure, namely what their chief spokeman, Rich Hickey, have elaborated over the years. The truth of the matter is that nothing you said here contradict with what Rich Hickey said. He said “Simple is not the same as easy”. So you were basically attacking a strawman that you conjure up to make yourself feel better.

The focus of Clojure is on simplicity. Apparently you have nothing to say about that. That is OK for a beginner. But it is borderline ludicrous for such a beginner to claim mastery of the concepts of Clojure.

You may not realize, but your lament of “lack of primitives” is precisely the point of a higher level programming language. Lower level languages provide just three primitives that is required of a Turing complete language: assignment, conditional and loop. Clojure provides you with more and higher level primitives, such as map, filter and so on. It has to be so in order to become a higher level language. A higher level language is just more productive for whoever has mastered it than lower languages, because the higher level primitives are closer to human conceptualization than machine-like conceptualization. For a person who have internalized the machine-like conceptualization of computation, here lies the difficulty of learning because one has to unlearn the habits and patterns of thought of machine-like computation. For a person without such burdens, there may not be such a difficulty, hence some people’s claim of Clojure’s easiness to learn. The jury is still out on that one, but many anecdotes of hiring junior developers who are fresh out of college, indicate that there’s some truth to that.

Another counter-intuitive truth about programming languages, is that the higher of the language abstraction, the fewer freedom they give you. Structural programming language takes away your “goto”, functional programming language takes away your assignment. In return, you are given simplicity. It takes a lot of real world experience to appreciate the benefits of simplicity though, so it is not really a selling point for beginners.

Richard_Heller

Mar '19

huahaiy:

The truth of the matter is that nothing you said here contradict with what Rich Hickey said. He said “Simple is not the same as easy”.

If anything, I’m the only one on here agreeing with him. That’s been my basic point this entire time. It’s not easy. I agree that once you get it down, the simplicity of it is nice. I wholeheartedly disagree that’s as easy to learn as languages who’s stated goal is to be easy.

huahaiy:

it is borderline ludicrous for such a beginner to claim mastery of the concepts of Clojure.

Y’all are confusing the concept with the implementation of the concept. Map is not a concept. The concept is to call a function on each item in a list. Clojure calls that concept map. I’m perfectly comfortable with the concepts, I use them in every language I use on a daily basis. Where I’m at right now with Clojure is not having memorized the 100 different names it gives to the different concepts.

huahaiy:

it is not really a selling point for beginners.

Again, exactly the point I’ve been making all along.

mvarela

Richard_Heller

Mar '19

Not true. I don’t use Python, I don’t really like it as a language. For ease of understanding and learning, though, it’s tough to beat.

IFF you have been exposed to imperative programming first, or you’re being taught that way.

The empirical data says otherwise. If too much OO knowledge is the problem, then beginners and non-programmers shouldn’t have a problem.

What empirical data? Most beginners are taught some imperative/OO language when starting out, so they think that way. Some unis (even in non-CS related fields) start out with FP, and their students learn with no further complications, too.

Map is not a primitive. It loops, calls functions, and modifies data. 3 different things.

This contradicts your previous statement about having grokked the principles of FP, I’m afraid. Map does not modify anything. It doesn’t loop, either, it recurses. Also, it’s not out of your hands, whatever you mean by that. You can compose it with other functions to control when and where the mapped function is applied, and for this, you need to simply understand the underlying concept.

It really feels like you’re just stuck in the imperative mindset, and are crapping over the language because you find it hard to fit in your mental model of programming. It is hard to change the way you think about programming (been there, done that), but there’s nothing inherently hard about FP (or Clojure) in and of itself. It really is a simpler language than Python, if you don’t come to it with a previous bias.

Peace out!

2 Replies

Webdev_Tory

Mar '19

I would like to see the statement “It really is a simpler language than Python” pursued with Rich’s definition of simplicity (= not complected/braided) kept in mind. How do the core libs of Python vs Clojure compare, for instance?

mars0i

Mar '19

It’s not necessary to memorize all or most or many of the functions that are useful in Clojure. I don’t know them all. I don’t even necessarily remember functions I’ve used before, if it’s been a while. That’s what clojuredocs.org, or the Clojure cheatsheets, or parts of clojure.org are for. If you’re disconnected from the Internet, find-doc, apropos, and doc in the repl are reasonable substitutes. Over time, I have gotten a sense of what sorts of functions are available, and I can then go looking for something like what I want. Or sometimes I just write my own custom version of what I want.

alanmarazzi

Mar '19

I just wanted to give my 2 cents without answering to anyone in particular. I happen to know Python very well, though sometimes I feel like I only scratched the surface, while with Clojure - though I learned it more recently - I know it: once you understand the basics of it you’re done.

Yes, you’re left with transducers and core.async, but the formers are already being ported to other languages and the latter, well Go is basically just it. So, after you understand these concepts as well my claim is that your Clojure code can actually go faster than regular Java (and especially Python) code. Why do I say this? Because with Clojure I don’t need loops, I just build transducers and then stuff them into a pipeline-something and that’s it. Boom. Parallel/Async processing.

Now try doing that with Python. Good luck. Asyncio is the craziest thing ever come out and makes everything so complex you want to simply pull your eyes out of your head and multithreading is very poorly supported. I have to add that I’m a data scientist/engineer, so usually my code is performance sensitive and with Clojure I was able to find the right tradeoff between performance, ease of development and maintenance cost.

Now about simplicity. Take at look at this: https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/svm/base.py 30. If you can understand this code ins and outs in less than 30 minutes either you wrote it in the first place or you’re a freaking genius. Python isn’t simpler than Clojure, it’s just that we’re used to stare at very simple scripts, but as soon as you have to get down to the serious stuff, well, so much for ease of use.

What the heck is ABCMeta? What about @property? Does it read as english? ‘At property’??? Is it a comment?

Well, ABCMeta is a class that you have to import from a separated module and use it to create abstract classes. @property: first off, it is a decorator. Guido didn’t like f(g(z(x))) notation, so now we have decorators. It is just a wrapper function called in a different way. Yes, it is a wrapper function that you use in methods inside classes definition to deal with properties and that returns new objects. That’s easy!

The point is that as soon as SLOC increase every language gets more and more complicated, by how much is the real matter. As an example, if you’d like to contribute to a library as complex as scikit-learn you need years under your belt of Python development, and for many it would be too overwhelming to do anyways. In Clojure, after a few months of development you can contribute to Incanter without many problems, though it is a much larger library in scope than scikit-learn (take the libraries as examples only for code complexity, to really contribute to these one needs expertise in data science and machine learning as well).

So Python is much easier to learn and to use for very simple stuff, it is almost unbeatable. For more serious stuff, good luck.

VIEW 1 HIDDEN REPLY

Webdev_Tory

huahaiy

Mar '19

Guys – let’s change the tone here. Personal attacks and slights are not cool and should not be part of the Clojure community. @Richard_Heller, thanks for putting yourself out there with what was evidently an unpopular opinion. Despite some of the cringeworthy responses, you have contributed to a conversation with many insightful perspectives, whether I agree with all of them or not.

VIEW 2 HIDDEN REPLIES

didibus

Mar '19

Webdev_Tory:

let’s change the tone here. Personal attacks and slights are not cool and should not be part of the Clojure community

Agreed. The topic at hand was inviting of diverse opinions. I think @Richard_Heller 's perspective was very insightful, and we’d be wrong to dismiss it as a community. I also appreciated all of the responses to that opinion, and the diverse perspective.

Lets focus on keeping things into healthy discourse, and not make them into debates. I don’t think anyone needs to be convinced one way or another, we can instead focus on simply understanding people’s angles, and opinions, respectfully, even without necessarily agreeing with them.

I also understand the people feeling a little challenged by the topic, and I think that’s also an okay feeling to have, this is a Clojure forums, full of people who love Clojure, hearing criticism, especially which we don’t agree on, isn’t always very nice.

Personally, I do think we should recognize a few things here:

1. Some people do find Clojure easy. That’s the case for me. I did not find it hard to learn, I found it quite easy to learn, and I learned a lot of new ways to model software through it, which I found quite simple and elegant.

2. Easy to learn, does not necessarily mean quick to learn. Clojure is built on top of an unfamiliar foundation, and each of its layers generally comes from more niche, less familiar theoretical basis. Learning it is like going back to school CS 101, first year, first lesson. This can be frustrating, especially to someone with already a lot of experience under their belt. Even worse, even the foundation of the foundation is unfamiliar, so some of the things you learned in elementary school and high school as your de-facto instinctive foundation won’t apply. So in some instances, you even have to go back to elementary school. Such as the prefix vs infix operators.

3. Unfamiliarity, having to go unlearn the basics, and re-learn them over again, can feel painful and tedious. Which might make it feel hard to learn. It is unclear here, if it is any harder then the traditional foundation was to learn. But, in some ways, that doesn’t matter, since it is not what elementary, high school, and standard CS programs, books and tutorials teach you. That means unfamiliarity will almost always be a property of learning Clojure, both for non-programmers just getting started, as well as experienced programmers, without prior knowledge in most of Lisps, FP, lambda calculus, persistent DS, lazyness and concurrency primitives such as threads, futures, stms, csp, etc.

4. Some people also find it very hard to learn Clojure. You can’t argue against that. People feel the way they feel. The question is, what can we do to help ease that feeling for them, as a community, in order to be more inviting of a more diverse set of people. @Richard_Heller is actually correct and on point in saying that Python will attract these people, where Clojure won’t. Now they suggest that it might be inherent to the way Python is, which makes it intuitively easy, where as the way Clojure is makes it intuitively hard to some (maybe even most) people. I can’t say I agree with that, but I also can not deny the possibility. Either way, I think it is clear that Clojure is not willing to change itself inherently in order to change this. Python on the other hand, has a tenet, and a goal to do so. But that does not mean there is nothing we can do to help. Better tutorial, more material, a stronger support group, access to content, all that will for sure have a positive impact on helping people overcome that initial hardship, no matter what the cause of it is.

On that, I’d like to leave new users learning Clojure with a few final notes:

1. If you find Clojure hard now, do know that it gets easier. The struggle disappears, and everything starts to make sense, and becomes really fun and pleasant. There’s no proof to this, only lots and lots of anecdotes from people who went through that same journey.

2. But, there’s no reason to struggle to the point of exhaustion and total frustration. Put it aside, and come back to it much later.

3. If you still find it hard, you most likely just havn’t gotten it yet, and done enough. I’ve mentored many people to Clojure professionally, and almost everyone one of them complained and moaned for the first two to six months (of full time work). Yet now they have Clojure stickers on their laptops, and can’t stop talking about how awesome it is. By the way, 2 months is 320 hours, and 6 months is 960 hours. So if you havn’t put anywhere near this much time, it might be normal that you still struggle.

4. And maybe you just don’t like it. At the end of the day, use a tool you enjoy using. I think one thing that the Clojure community can pride itself in, is that we don’t downplay other languages (except Java :p). There’s trade-offs to Clojure. Part of those is why Clojure is an incomplete language. The ugly parts we leave to Java and C# and JavaScript, and recognize it is still best to use them for it. By nature, Clojure recommends polyglot knowledge of programming languages, where you are expected to learn at least Clojure + 1 (either Java, JS or C#).

And remember to have some fun! :partying_face:

1 Reply

mars0i

Mar '19

Thanks for those comments, @didibus.

didibus:

Better tutorial, more material, a stronger support group, access to content, all that will for sure have a positive impact on helping people overcome that initial hardship, no matter what the cause of it is.

I keep thinking about The Little Schemer (née The Little Lisper). There are Clojurifications of it on the web. It’s a weird book. There are quirky questions on the left, and answers on the right, and you are supposed to cover up the right side while you think about the left side. You don’t even need a computer, although it’s nice to experiment at a REPL, too. I don’t think most programmers would be willing to work through it in the way that it was intended, and maybe they don’t need to do so. However, when I was a fairly inexperienced programmer, but had been studying Common Lisp on and off for a while, working through The Little Lisper was what, for the first time, allowed me to grok recursion.

The book would not be enough to properly learn Clojure, even rewritten in Clojure. I wonder, though, whether some sort of style like that could help people overcome the initial hump to Clojure programming for most people, if they were willing to sit through the process. The Little Schemer style is so slow, and so simple and friendly, that I have the feeling that it could overcome any countervailing tendencies, if the reader were patient. I don’t know.

1 Reply

porkostomus

Mar '19

@eccentric_j I’m not sure how much I’m able to contribute to this discussion but it does seem quite fitting right now because, before choosing Clojure I did have a few months of Python experience, and recently have mostly gone back to Python for a couple of reasons.

As far as the language itself I prefer Clojure, hands down. I chose it in order to learn what I recognized as the most effective programming habits, and absolutely love everything about it.

Clojure as a (nearly) first language has been really interesting. I find that the things most often complained about Clojure being “hard” do not seem so to me at all, because I guess I lack reference. It’s all new.

The difficulty that I’ve been encountering with Clojure is finding work, since most other applicants are way more qualified than me. So I’ve been spending time getting other languages under my belt to round out my portfolio.

Besides experience programming, I’m also lacking even a basic math education, so a few months ago I began teaching myself algebra while using Clojure to assist me by writing functions to perform the computations and putting together notebooks as web pages with KLIPSE snippets. While trying to write my own solvers and whatnot, I thought to look at other languages that are more focused on symbolic computation to see how they did it. First I used Wolfram (Mathematica) and fell in love with the notebook interface, but not its proprietary model. So then I found Jupyter notebooks, and have been happily using them with Python ever since. I know that there is a Clojure kernel for Jupyter, as well as other live notebooks, but for now I’m having a great time exploring the Python data science stack, even though I don’t particularly like the language!

I’d love to be able to just use Clojure for everything, but right now I just need a job. I started doing all this 3 years ago in order to get myself off the street, and still have yet to write any code for money so my situation is a bit… desperate. It occurs to me that if finding immediate entry-level employment is the goal, trying to do that with Clojure may not be the smartest choice.

1 Reply

porkostomus

mars0i

Mar '19

I actually started writing one of those! That’s how I got my nickname, “The Crazy Clojurian”!

eccentric_j

porkostomus

Mar '19

Thanks for sharing your experience @porkostomus. To some degree I think you’re a bit exceptional with your drive and studious habits, I still kill time with your Minesweeper rendition from time to time. However your experience is a valid counter-point to over-thinking how difficult learning Clojure as a first language actually is (something I’m guilty of): It’s at least possible!

Topic detour:

If you did want to give a Clojure notebook a try, Next Journal and Maria.Cloud seem really solid:

https://nextjournal.com/a/KT71s88aKdZdDgu8xRzp6/edit 8

https://maria.cloud 2

Additionally I drafted a small library to turn clj files into notebooks:

GitHu b

eccentric-j/book-report 4

A Clojure library that turns files into interactive notebooks to make learning from books easier. - eccentric-j/book-report

Back on topic and not addressed to anyone specifically:

I actually failed learning Clojure the first time. I had just begun grasping functional programming and had a friend who was really into Clojure a few years back that made me think it was worth trying. Within the first few chapters of Brave & True I found myself more and more frustrated – it just didn’t make sense. I liked the syntax but the solutions just were not something I would ever arrive at myself.

Then I spent about a year or so studying functional programming in general and applying the techniques in my day-to-day JS. Eventually I wanted to find a language that was designed with functional programming principles in mind where as JS will always take a strict amount of discipline from every developer that touches our codebase to keep it cohesive. That’s when I found my way to Clojure again and remembered I had a copy of Brave & True. This time around I had no problem transitioning! I had incidentally learned most if not all the required concepts to understand the solutions in Brave & True and was able to solve the exercises I attempted.

That said learning Clojure as a programming language wasn’t any more difficult than any other language I’ve wrestled with. In many ways it felt easier not having to memorize a bunch of arbitrary symbols and their order of importance. Learning to think functional however, that was a bit of a mountain, it took some will power to want to relearn everything in a different paradigm – almost starting from scratch with the baggage of my previous experiences weighing me down. Early on it was easy to get stuck with Clojure and think, “Ugh. I could solve this so easily in JavaScript.” Now when I use JS in my day job I think “Ugh. This could be made so much more simple in Clojure”.

Phill

Mar '19

Richard_Heller:

…First, the original question was how to sell Clojure to Python developers to get them to consider switching. To which somebody said the ease of learning is a reason.

Where was that?? There was a post saying Clojure was kind of easy after working with FoxPro. I, for one, was not steeped in FoxPro and the first little while with Clojure went somewhat as you described. To put it delicately, I really would not suggest that the untutored getting-started experience is the selling point. But the throes passed. And that’s it, in a nutshell: the throes pass! Before Clojure, I had used only languages where the more you know, the harder they get.

plexusgroundskeeper

Mar '19

Hi everyone,

Thanks for having this elaborate, considerate, in-depth discussion. This really is what ClojureVerse is here for.

Comparing two different technologies is often a little contentious, and we’ve seen in the past that as these discussions drag on the level of discourse tends to drop. People start impulsively replying to specific turns of phrase, without keeping the full context of the discussion in mind, which admittedly becomes hard when there are over a hundred preceding posts. This is also the reason we auto-close topics. At a certain point we have to agree that the discussion has been had.

I’m not closing this topic just yet, but I’d like to ask people to show some restraint. Please consider carefully before posting whether you’re bringing something new to the table, or if you’re reiterating points already made.

Please also keep in mind that on this forum we value a friendly environment above everything else. When someone has an opinion that wildly differs from yours, then make an effort to understand why a person would come to such a viewpoint. In what context, and with what background would you come to this wildly different conclusion? This is how we learn from each other, and is infinitely more fruitful than trying to change the other person’s mind.

In the end we also have to accept that everyone has some bias, and that even discussions about technology can never be 100% fact-based and objective. Rather than becoming defensive when our beliefs are challenged we should use this as an opportunity to examine our own biases.

I found a lot of good food for thought in this thread. Thanks @Webdev_Tory for starting this discussion, and @Richard_Heller, @didibus, @mars0i, and the other two dozen contributors for sharing their insights.

ronin78

Mar '19

I might have an interesting perspective here, since I am not a programmer by training or trade and have kind of glued together a bunch of stuff to do what I find useful or interesting.

I started with imperative programming, both Perl and Java, so I also struggled at first with Clojure. I’ve been trying to think about why, and I think that part of it was not really knowing where my data was. In an imperative language you define a variable and then you modify it, so I feel that, no matter what is going on in my code, I know what my data looks like and can output it easily and examine it. Of course, that can be a downside too; I don’t know how many times I accidentally incremented the wrong variable because I had forgotten to change a variable name somewhere (that might not happen to experienced programmers). So when I started with Clojure it was a struggle at first to understand that my data is, you know, in the function. So how do I get it out? Sometimes I still forget that I can view the first few calculations in a function by “take”-ing from a lazy sequence.

That said, I’ve tried to teach two sets of non-programmers in an imperative style and they have a lot of trouble with Python. My wife once asked me why you would define something to be zero and then keep adding 1 (or whatever) to it, instead of just adding a list of numbers. The latter approach is more FP, and she has found R to be more friendly because it has more of a nested function structure and she doesn’t have to remember where her data is (mostly). My non-programmer accounting students struggled with Python for similar reasons, and I also think that they might find a FP approach easier next time around.

For myself, I switched to Clojure when I found that my Java code was getting too big and clunky, so perhaps I finally crossed the complexity threshold that others on here have mentioned. I had a bunch of classes, and I couldn’t always remember what they did, or what I called the methods, or how to pipe them together. As I said, I struggled a lot with Clojure at first because it was hard for me to see inside what I was doing and I hadn’t really grokked the abstraction of it. Now I much prefer using Clojure, and recently rewrote a complex piece of ABM code, for which I was using MASON in Java before, in like an hour using only native Clojure functions.

I very much appreciated @Richard_Heller’s comments. I am surrounded by Python programmers, and I am not sure that I will be able to convert them. Most of them care only about getting something, usually relatively simple, done as quickly as possible. So they often don’t reach above a certain level of complexity. It is also easier for them to find Python code that they can cut-and-paste on SO or on the web, and they don’t particularly care how it is done. I am actually interested in the conceptual framework, and that is part of the reason why I am here (and why a non-programmer would watch Rich Hickey lectures on abstract CS concepts that have little or no practical application to what I do day-to-day).

2 Replies

Webdev_Tory

Excellent thoughts; I particularly like your exercise of going over your early learning experience. I also began with Java and Perl (and some C, Javascript, and PHP too). I’ve not thought deeply about this, but will give it some thought and see what I come up with. I suspect my journey reflected more the fact that I learned about Lisp long before I learned about functional programming.

alanmarazzi

I somewhat share your experience, I myself am a self-taught coder, but I started with R, then moved to Python and finally to Clojure (leaving aside languages I use much less now). R is really a few steps away from Clojure or another LISP and that experience has helped me a lot with learning Clojure.

Webdev_Tory

Mar '19

Excellent thoughts; I particularly like your exercise of going over your early learning experience. I also began with Java and Perl (and some C, Javascript, and PHP too). I’ve not thought deeply about this, but will give it some thought and see what I come up with. I suspect my journey reflected more the fact that I learned about Lisp long before I learned about functional programming.

linpengcheng

4

Mar '19

This is the two most important reasons why I like Clojure.:

- Simple and smooth data manipulation.

- Simple, flexible S expression syntax, zero syntax learning costs, it can focus on work, not subject to syntax and its upgrade interference. It’s like a Markdown in the programming language world, but it’s surprising that Markdown is popular, and S expressions are not popular,

- Is S expression simpler and too more expandable than Markdown?

- Or is the C-like syntax habitually too strong?

- Simplicity is the ultimate sophistication.

:smiley:

alanmarazzi

ronin78

Mar '19

I somewhat share your experience, I myself am a self-taught coder, but I started with R, then moved to Python and finally to Clojure (leaving aside languages I use much less now). R is really a few steps away from Clojure or another LISP and that experience has helped me a lot with learning Clojure.

TristeFigure

1

Mar '19

I decided to learn Clojure after having learnt Objective-C (I wanted the C preprocessor to be able to handle C itself as a macro language) and was already into quite advanced programming stuff (last thing I did in Objective-C was a library to code in an aspect oriented fashion).

I started learning Clojure straight with 4Clojure challenges, no book, just a cheatsheet of common Clojure functions and apart from having to learn how to use basic items like let from the problems’ solutions which was a little disorientating at first, the biggest adaptation I had to do was to think functionally, i.e. with code flow explicitly in the form of a directed acyclic graph.

At first, I literally had to draw the graph prior to writing code, then I quickly got used to thinking in these terms. Eventually I learnt about libraries like Prismatic’s Graph that explicitly treat and present code as a graph.

This is what I love with Clojure (and what somehow prevents me from using other lisps): the flow of syntax matches the flow of data most of the time. To put it in other way you have several “domains”, that of unexpanded code, that of code, and that of functions, with steps that functionally link one domain to the next one:

unexp. code -- [reader-macros + macro-expansion] --> code -- [compilation] --> functions

The items in these domains are linked through a directed acyclic graph (respective to each domain). Code, both expanded and unexpanded, is tree-ish. Ditto for functions. You have a many-to-one, branches-to-root, inputs-to-output underlying structure to both.

Now what’s interesting is that transformation between these domains preserves order relationships between elements from the source domain to their counterpart in the target domain so that you can trivially reason on order relationships between items from distinct domains.

- A macro can only modify code that is <= to the processed form (&form): it cannot transform outer code. This is due in part to the fact macros are functions under the hood.

- Side-effects excluded, data transformations only happen downward in functions too: a function cannot change a variable outside of its scope, and by scope I mean lexical, i.e. syntactically ordered, scope.

What does this lead to ?

To put it in other words, each step in transforming Clojure code and data, from reading it to compiling it, as well as “mutating” it (i.e. creating a new version of it), can be seen as graph transformations on “structured” graphs (i.e. DAGs), specified as DAGs themselves.

And this is really interesting because this is the shape of causality. I often hear that no matter what, FP is implemented on imperative bases. However true this may be, an imperative program where cause and effects are fully tracked and analyzed will take the shaped of a DAG.

jwr

Apr '19

Richard_Heller:

Clojure doesn’t offer anything over the existing languages other than personal preference. It doesn’t give significant performance improvements or make things significantly easier. There aren’t any pain points that go away by switching to it.

I respectfully disagree. Superficially, if you just look at syntax, what you wrote is true. But if you consider building real systems with it (especially on a larger scale), Clojure offers a lot over other languages/ecosystems, and I get a lot of significant performance improvements if by “performance” you mean building real working large systems with a small (in my case, one-person) team. If you consider features like core.async, transducers, immutable data, built-in sequence abstractions, and ClojureScript (the elephant in the room), you can no longer equate Clojure to “other languages”, simply because there isn’t anything quite like it.

As to advice on learning/working with a language and finding jobs, I would always suggest to learn as many languages/ecosystems as possible, to broaden your views. Get the “Seven languages in seven weeks” book and work through it. Then get the “Seven more languages in seven weeks” book and work through it. Then write applications in some of these languages, which will start giving you a feel for how they work in practice. Do not box yourself as a “Python programmer” or a “Clojure programmer”.

3 months later

MalloZup

Jul '19

“Stop treating beginners, junior devs, and all devs in general like they can’t learn hard things and learn to ride a horse, even a really high one"

I can’t agree more with Didibus.

To me the most problem in our tech-industry is the short-term perspective of projects.

In this way, everybody want to pick-up the most easiest thing for doing results in short-term, which leds to throwing away Products every 1/2 because they becomes unmaintainable.

E.g the python 2/3 migration history, in legacies systems is really hard to maintain.

I picked up python, but one could do the same for other lang (golang/python/ruby/scala) all this which introduce massively breaking changes.

(speaking from experience)

TristeFigure

1

Jul '19

And I while I agree to

Stop treating beginners, junior devs, and all devs in general like they can’t learn hard things and learn to ride a horse, even a really high one

I also agree with

Richard_Heller:

I feel one point that’s getting overlooked in this discussion is the turnover rate in today’s job market. Developers don’t stay long in one place, for one reason or another. Using a language like Python ensures the next wave coming in will be able to get up to speed and contribute quickly.

All devs are not equal, and under the right conditions, one can be 2x, 3x, 4x … more productive than another one. I’m not even mentioning the 10x shorter 10x as powerful lisp program you can write in 10x less time.

So @Richard_Heller, why not pay them really well, foster their talent and encourage them to start their own business and finance it, in order to have a different kind of turnover, one that is not seen as a leak to the Big Market from Outside but as an accumulation of knowledge, skills and code within a web of sister companies ?

Yogthos

seancorfield

Jul '19

Another thing to note is that any large project can be broken down into smaller independent components. Small components are easier to reason about and maintain directly leading to higher code quality. It’s easier to onboard people to work with them, and you can reuse them for other projects. Smaller teams also have way less communication overhead because there’s less meetings, emails, and less need for coordination in general.

1 Reply

John_Newman

Jul '19

Lambda calculus strikes a better balance between human readability and machine readability. And being able to reason about one helps us reason about the other.

Algo’s sales pitch against lambda calculus is, “hey look, our statements look more like spoken language. These various precedence rules are the middle ground between register statements and natural human speech.”

The idea was that by incorporating parochialities of human languages into each statement, we’d be able to bring programming to a wider audience. Parochialities of infix notation. Various other parochialities of operational order of precedence. Intuitions about how humans communicate, baked into the language - all while trying to hide the underlying datastructures that don’t really obey those intuitions.

The other argument for algo-based languages is that most register-based CPUs provide a mostly update-in-place architecture, using store and load statements that sorta-kinda look like really short human sentences. So there’s a short path between those and the illusion of spoken language commands.

Elixir is a good corollary example here - the syntax inherits from algo dialects, but it provides an easy pathway to homoiconically understanding how the compiler is interpreting the syntax. This is why you can do macros in Elixir. I’m betting most Elixir programmers know how Elixir works better than most Java programmers understand how Java works.

In the end, these languages are just different colors of lipstick over the same pig, right? I just find that I’m able to understand a language a lot better when I also understand the AST of it that the computer is working with. All the other syntactic parochialities are just maybe-conveniences for specific domains.

MalloZup

Yogthos

Jul '19

The only thing with indipendent or smaller components, is to make this component really indipendent from each others. Otherwise you have even worst pattern as monolithic repos. Where each small things depend on each other. But a part from that I belive that small is beautiful, either on team size and on projects. Projects with lot of devs are not effective and also really confusing in term of design

daslu

Jul '19

Hi!

For anyone following the discussion here (must admit I lost track a bit :blush:) –

This Thursday we will have a web meeting 3 about clojure<->python interop, introducing libpython-clj 7 by @cnuernber and panthera 5 by @alanmarazzi.

Indeed, the main orientation is data science, but I think that anyone interested in bridges across languages will find this meeting useful and fascinating. At least, that is how I feel after hearing a little about the speakers’ plans.

Anyone interested?

(would be great if you could register in advance)

(edited: link)

3 months later

Andy_Wootton

Oct '19

I have taken a LONG time away from programming. I have written about 3 TDD tests in C#. When I started to learn Clojure, I couldn’t understand how to do testing but it is conceptually much simpler. A function should return exactly the same value every time. If you change the code, has the value changed?

6 months later

Closed on Apr 7, '20

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.