What do beginners struggle with?

That’s a confusing use of the term async, but I understand what you mean, except it seems all your calls to A and B are actually synchronous in this case, or at least that’s what I gather?

In any case, it doesn’t seem to be the issue is with async, but just managing state. For managing state, an atom is a good choice. In your case, you want to cache the auth-token, and atoms are great for that, you could also look into memoize and company. Technically you can also leverage closures, deftype or recursion, but those are more advanced and honestly I wouldn’t say they are better, atom is what you want in my opinion.

Yes there is. You want to use clj-refactor Home · clojure-emacs/clj-refactor.el Wiki · GitHub

Once you have that, there’s a feature called Magic requires, it’ll automatically add the require for common alias, and if you’ve had the alias for it already in another namespace, it’ll pick that up as well, and you can add your owns to cljr-magic-require-namespaces

So basically if you type str/ the require for clojure.string aliased to str will be added automatically and the ns declaration will get re-evaluated as well so you can start using it immediately at the REPL.

Finally, the one you probably want the most is add-missing-libspec see here: cljr add missing libspec · clojure-emacs/clj-refactor.el Wiki · GitHub

There’s other refactorings available in it as well that can be handy.

Emacs is a bit of a beast, but can be quite productive for Clojure once you figure it out. I recommend a combo of packages for Clojure:

clojure-mode + Cider + clj-refactor + smartparens + aggressive-indent-mode + adjust-parens + flycheck-clj-kondo

Clojure-mode does syntax highlighting, indentation, and some basic refactorings. Cider gives you integrated REPL, debugger, documentation, auto-complete, code navigation and code browsing, clj-refactor adds more refactorings and what I mentioned before, smartparens does bracket management and structural code edits, aggressive-indent-mode keeps everything auto-indented and formatted all the time, adjust parens lets you wrap/unwrap code using tab, and flycheck-clj-kondo gives you very powerful real-time linting.

Setting this all up is a bit tricky, but that’s part of learning Emacs. I also use Spacemacs and have other customizations that are not Clojure specific per-say but add a lot of features to Emacs like a project panel, smart jumps in the code, git integration, command auto-completion, etc.

3 Likes

Wow thank you for this, I will look into those emacs packages.

And yeah I guess I was using the term ‘async’ incorrectly. What I mean was just making ‘network’ calls? Anyway, I’m curious to know how you’re supposed to manage network data as state in other fp languages to that don’t have atoms. You mentioned closures/deftypes/recursion but I don’t have the knowledge to know how to apply those to this situation, but it is something to keep in my awareness, thank you!

They’ll most likely all have a construct similar to an atom, for example Haskell has TVar, MVar, TMVar which are similar managed safe mutable containers like Atom and Ref are in Clojure. This is because state is often unavoidable, and memory is not infinite, so at some point you need mutation, but what FP languages do is isolate that mutation and manage it so you limit its impact on program complexity and safety.

Now probably what you want to hear as you’re trying to keep things purely functional and I feel your question is… but aren’t these mutable state containers non functional?

Well the answer is to keep to a pure FP style, you need to model things as a data-flow and pass state along. You maintain state because it’s constantly passed along to the next thing running or waiting. Sometimes that’s more ackward than good though, and lots of frameworks in FP languages won’t do that, they’ll use a managed mutable container like an atom.

So here’s the gist:

waitForNextCommand(state[])
-- command, state -->
if state missing token
  -- state[] -->
  getTokenFromA
  -- state[token] -->
  callB
  -- state[token] -->
  waitForNextCommand(state[token]) ;; recursive
else if state has token
  -- state[token] -->
  callB
  -- state[token] -->
  waitForNextCommand(state[token]) ;; recursive

Now there is no global state, and no mutable containers, only functions of immutable input to output calling each other in a data-flow which is recursive, yet you won’t call getTokenFromA if you already have a token.

That said, waitForNextCommand won’t be pure, and that’s normal, at the boundary something has to be impure as it interacts with the user or external world.

2 Likes

Thank you, a clear and precise explanation. If you want to copy/paste that answer to my q on stack overflow, I’ll accept it. I haven’t seen anywhere an explanation that made sense to me yet.

Hi there. Total noob here, and totally new to Clojure too. When reading this, please remember that I am not a dev, computer whiz or someone who has enough hours in the day to put in maximum effort. Apologies if this reads like a rant. It isn’t. It’s more frustration than anything else. (And apologies if my English. Second language, and all that.)

So, the difficulties experienced by me, as a beginner (and a bit of an idiot, I am not ashamed to admit):

  1. Getting the thing to start.

This was tough for a complete noob. Installing Java (and Java vs OpenJDK, whatever that is), and choosing an editor and getting all that to work. Not much fun. Then, clojure.org says I have to install clj, whatever that is. But there is only an experimental clj for Windows. So skip that. Then there is leiningen and boot, and I have to choose. I didn’t even understand what these things are supposed to do, but I figured out that leiningen has something to do with the hallowed REPL, so install it I did. (Oh, then there is also a REPL and nREPL, socket REPL… so much to figure out.)

tldr: I have to make choices about a bunch of stuff I know nothing about and struggle with getting them to work.

All this, and I haven’t even written a line of code.

  1. Resources for real beginners

Most of the Clojure books for beginners seems to be aimed at people who are already proficient in some programming language or another. I am not one of those. Even Clojure for the Brave and True, which looks like the book most people recommend, assumes this. It starts of slow enough, then throws the Hobbit example at you and (like someone else in this thread said) hopes something sticks. Then it tells you to go out and code! I need some more hand holding. Unfortunately, a lot of beginner resources point to git something or another (yet more time wasted learning something else that isn’t coding).

  1. Error messages and documentation

Enough has been said about this, so I won’t elaborate. But it gets in the way of a noob trying to follow the above mentioned advice of going out there and coding.

  1. The REPL

It seems like the REPL is a big deal, because every text on Clojure mentions it in the first paragraph. But this is also a bit confusing. Why is it so important? What makes it so cool? And why is it that, beginner books tell you to fire up lein repl and type to your heart’s content, just to be told by the cool Clojure kids to never write in the REPL? Fair enough, this thread has links to some videos which I’ll check out, but why aren’t there any noob books that incorporate this?

In summary, when reading up about Clojure, I read all about how the syntax is simple, how FP is awesome and how it makes programming fun. How it is a great language for beginners. It might be all those things, but it certainly isn’t batteries included. Also, please note, my intention is not to whine. I still haven’t decided to drop Clojure for Julia or Python or something - I’m reading beginner threads, after all, so I’m still hopeful that I’ll be able to find a way forward.

4 Likes

I feel your pain. Clojurescript is my first programming language and all what you said is true. My only advice is to be patient. It’s not easy to get started but over time a lot of stuff makes sense. It is said that Lispers decided to take all the pain up front, but after a while you will be rewarded with a stable language with stable deps and all that.
Some tools I can recommend: Shadow-cljs for Clojurescript, Calva in VSCode for a nice Clojure setup and babashka for CLI stuff (and more). They helped me a lot!

2 Likes

Thanks! This is great stuff for us who want to help beginners struggle less. I do hope you will persist in checking Clojure out despite the lack of material for the total beginner.

I especially recognise the confusion around the REPL and various REPLs-this and that-REPLs. And, yes, it is a bit unfortunate that so many tutorials guide you to a REPL prompt that you are later not supposed to use. This is why Calva’s Getting Started REPL guides you to an editor/file connected REPL. (As you are a Windows user, I should probably tell you that it will not work if your Java is installed with Oracle’s installer. They have a bug there before JDK17.)

3 Likes

Thank you for the suggestions and the encouragement, Michael and PEZ. I shall check them out.

But it does speak to my initial point that Clojure might be good for beginners, but it is by no means beginner friendly: lots of tools and tidbits I can download and figure out, yet nothing actually helps me learn how to code in this language (or figure out what I’m doing wrong when I try applying what I’ve learned).

Beginner resources are… hard. I don’t feel like plotting shapes with a pretend turtle (been there, back in the day when Logo was an actual language), but that means I’m stuck at being a little teapot, because what seems to be the most beginner friendly book out there assumes a noob can go from
loop [iter 0]… recur (inc iter) ; easy enough
to
loop [vector] [some other vector] [yet another vector]… recur ([vector which has nothing to do with anything in the loop point] (set stuff into other stuff and call everything “parts”)
like it makes perfect sense.

Trying to write anything on my own is equally jarring. Clojure says I see your effort, and I raise you a stack trace, a mile long, which you won’t understand. Sucker!

The whole business reminds me a bit of the stories I’ve read about installing Arch. “If you can’t figure it out on your own, you should probably be on Mint.”

Sorry, I sound whiney. Not my intention. Since beginner struggles is the topic, and I’m a beginner, maybe what I say will help the cool Clojure kids make the language, and experience, more accessible to future beginners.

(Btw, thanks for being positive and helpful. This is my first interaction with the community, you lot are making it a good one.)

1 Like

Since Clojure is a hosted language – both on the JVM and on a JS engine (browser or Node.js) – it’s never going to be easy on its own for a complete programming beginner, unfortunately, because you will have to learn enough of the host ecosystem to be able to figure out how to navigate that boundary, even where Clojure tries to hide it fairly well. And you’re right, all of the Clojure tutorials seem to assume some level of knowledge of at least one other programming ecosystem :frowning:

There are a few editor setups that do a good enough job at hiding the underlying machinery that you can make progress without having to learn about Clojure installation and REPLs – but even they still assume you have managed to get a JDK installed (and, as @PEZ notes above, even that can be fraught journey with some versions on some platforms). And there’s nothing whatsoever about getting “an appropriate” JDK installed that is beginner-friendly :frowning:

There’s also the issue of operating systems. Despite all the progress made over the years, Windows is still very much a 3rd-class citizen in the Clojure world: 53% of Clojurians use macOS, 37% use some flavor of Linux. Of the remaining 10% on Windows, it’s split half-and-half between folks using WSL2 (i.e., hosted Linux) and folks using Powershell. Working with VS Code and Clojure is much, much nicer on “Windows with WSL2”, in my experience, and again most of the tutorials out there assume macOS or Linux not Windows – but getting a good development workflow set up on Windows/WSL2 is not something for a complete programming beginner :frowning:

And as noted here (and in the Hobby Programmer thread), the initial learning experience with Clojure is nearly always couched in terms of typing into the REPL, which only gets you so far. To really work with Clojure in any productive way, you need to have an editor setup with a fully-integrated REPL (that you never type into!) so that you can evaluate code from your editor with just a hotkey and develop your app “live” as you type code into your source files. And for debugging etc you often need (or at least some people want) additional dev-specific libraries and tools. It’s a huge hill to climb from just “typing into the REPL” and, again, a mountain for a complete programming beginner :frowning:

7 Likes

Just a random thought:

What if we had a downloadable virtual machine (like a VirtualBox VDI) that contains everything a new person to Clojure would need? For example, preinstalled and configured VS Code with Calva, Emacs with Cider, example projects, empty starting project, etc.

The advantage of this is that it would ensure we have a common starting point for anyone that wants to try out Clojure, with a environment that is set up in a way to encourage good development practices (like using the REPL in the right way).

The main problems I can see is that: (1) it will require Windows users to use a Linux distribution, (2) big download, probably several GBs, (3) require new users to install VirtualBox.

The easiest way to get this set up would probably be to use something like https://www.vagrantup.com/ to set up an environment with everything needed to get started with Clojure development.

If you are a beginner, is this something that you would be interested in?

5 Likes

When I was frustrated with Clojure I did a bit Python and lots of Javascript. I learned a lot there too. The good thing with Clojure is that everything is pretty stable and the build tooling is much better. When you are stuck you can pause a project and resume working on it months later when you learned enough to start again. Projects usually will still work unless for example in Javascript land where deps break too often to make working on long time projects enjoyable.

2 Likes

I guess OpenJDK 16 and Calva play nicely together on Windows, because I just got the thing up and running! Thank you for the suggestion, PEZ

And @seancorfield I must say, I think I am starting to see the appeal of not typing in the REPL! Typing everything in the REPL wastes a bunch of time, for one.

Alright, back to the grind. Thank you for the help and motivation, everyone.

5 Likes

Great to hear you are up and running. It is very unfortunate with that JDK bug, but at least we now know about it.

Yes! I think trying to get it down to zero-installs is the way to go. There actually is a ”virtual” machine like this: Gitpod. I’ve updated my Rich 4Clojure project to work there and also updated its README to try to make it more accessible to beginners.

It would be super nice to get some feedback about how this might work out for a beginner. Can you give it a spin @jaco ? And all of you, of course.

1 Like

Busy working through the 3 help files now. Looks awesome. So far, it helps that I don’t have to install anything.

1 Like

Hi folks,

I read this thread with interest, especially the replies by @HolyJak @PEZ and @seancorfield. As a complete #Clojurenoob, this thread really resonated.

But as I read the thread, I realise that there are beginners, and there are beginners. Some of the beginners here make me feel that they are misnamed: they might be beginners in Clojure but they definitely feel very experienced as developers!
And it dawned on me that, maybe it makes sense for us to clarify further what we mean by beginners.

I will speak first for myself: I am a beginner-beginner, in that I completed an online web dev bootcamp, so I know basic HTML, CSS and Javascript, but haven’t really practiced those because I have an instinctive feeling that I will develop a lot of bad habits… so I basically followed the web tutorials, and can do some very basic commands. But I really disliked the messiness of JS, which feels very unclean and untidy mentally: very hard to debug… I only started last year, so am really a complete noob not just in Clojure, but to the world of programming in general.

Besides me, there are people who have a couple of years’ experience in other languages. They are then exploring Clojure. I think they are the next segment.

Then there are beginners to Clojure, but who are highly experienced in other languages, some with 10+ years’ experience. I suspect their needs will differ from the above two categories.

So when we talk about beginners, it really spans a spectrum, each with different needs.

I suppose the corollary question in my head is, is there a segment of beginners that y’all want to focus on first?
Related to that question, is the question of which segment of beginners should y’all focus on first? (I don’t have answers to the questions I am raising btw)

I also recently read this (great) book on open source software and how it has changed a lot thanks to Github and the rise of Javascript: the book is called Working in Public. In there, the book talked about how the nature of OSS has changed a lot, and how the rise of JS has also meant that many maintainers struggle with dealing with HUGE numbers of low-quality pull requests.

What I thought interesting was the characterisation of the different types of communities:

  • Federations (high user growth, high contributor growth) → Rust, nodeJS, Linux
  • Clubs (low user growth, high contributor growth) → AstroPy, but also Clojure, Haskell, Erlang
  • Stadiums (high user growth ,low contributor growth) → Babel, webpack
  • Toys (low user growth, low contributor growth) → ssh-chat

I suppose the corollary question is what segment or direction the Clojure community wants to go, and what type of beginner growth aligns with that?"

Again, I’ve no answers, just posing the questions off the top of my head. My instinct, though, is that we probably don’t want to end up being a stadium-type community…


For me as a beginner-beginner, the hard parts are learning all the basics:

  • tooling (especially finding a suitable editor, which was much harder than expected, and then setting up a REPL. I have found the IntelliJ + Cursive so far to be the easiest and most straightforward for me: initially I found Atom + Chlorine, but sadly it does seem that Atom is dying…)
  • error messaging is super opaque: they sometimes read like exclamations from Marvin the Martian to me
  • I initially also lost a bit of time wondering if I should start with Clojurescript instead of Clojure, since I know some JS. However, it’s actually a lot easier to get the tooling setup and done for Clojure than Clojurescript, so I’m taking the one-fire-at-a-time approach, and focusing on learning the language first and foremost.
  • the lack of a structured pathway with examples that I can follow. For me, I found some of Eric Normand’s videos to be super good, but they also strike me as being a bit too deep into computer science concepts for some people (I love them btw). Concurrently, I am also working through The Clojure Workshop, which is actually a REALLY great way for me to learn (as I learn best from seeing how someone does something and trying to replicate it).
  • I think what will soon follow is trying to really understand HTTP (underlying Ring), Clojurescript, etc.

But can I just say that, while the learning is tough, it is also super rewarding and I really appreciate just how friendly and helpful everyone is, on the Clojurians Slack and also on this forum? It’s amazing to see the degree of generosity and general kindness. :slight_smile: I really appreciate that, and only wish my Clojure skills were better so I can give back and pay it forward.

Peace out.

7 Likes

Hello! And thanks for this elaboration. There are so many great observations and I will certainly bookmark and consult it while working with these things. You are totally right about that there are different meanings of ”beginner”, and you provide great tools for thinking about it.

Towards the question about where the focus can be: I can only speak for myself, of course. To me it is ”all of them”. While I certainly see that we need to cover different bases for different journeys, my driver is:

You want to pick up Clojure and you struggle?

I think it is super important for us as a community to try to figure out what kind of journeys there are, and then for each one of us, as individuals, to pick a thing or two to run with.

That said, it is really intriguing to think about what we can do to make Clojure a delightful choice for learning to code.

As for your own hesitation about picking up bad habits. I don’t think you should worry too much about that. It’s inevitable, and it will happen at every stage, and never stop happening. The remedy is to keep doing stuff and get feedback and adjust. Without feedback we are all quite blind.

6 Likes

Thanks @PEZ!

That’s a really generous starting point, and I really appreciate it. :slight_smile: Thank you!

I think I can really comment on this only after I have more experience. But just off the top of my head, I think the biggest differences I’ve encountered so far are really symptoms of the different way of seeing. Like immutable data. Or the lack of for-loops (or “this”). Or the norm of “asking the REPL” if you have any question if a function could work, resulting in the very rapid, bottoms-up, iterative approach of RDD. It is really very different from anything else I’ve seen out there.

And I wonder what will happen if we have programmers who start their programming journey/career with that way-of-seeing instead of the current norm.

To clarify, I meant picking up bad habits from the web bootcamps (e.g. using “this”, or using global variables in JS). I also found myself quite uncomfortable when I learnt those, because while they got the stuff done, it just felt like… a trap? I don’t quite know why, but it just felt mentally untidy.

1 Like

As someone who’s first general-purpose learned for real was Clojure (I started learning Python, didn’t click with me so I dropped it, then learned R for work and loved it) I still struggle with Java interop, because I have absolutely no clue about Java. The rest of the language made total sense because I was already doing FP without knowing it. Mutability, classes, types are the things I find weird and hard to grasp “what problem would I fix with that”. But I’m aware this is not the majority of people.

5 Likes

Crossposting:

3 Likes
  • core.logic should be archived: it’s a rabbit hole, nobody uses it in production, the only introductory book is written in Scheme, and the documentation looks abandoned. You’ll get a better price when you sell 10 intact coffee cups than when you sell 10 intact coffee cups plus 2 broken coffee cups.
    Datalog, in contrast, was a revelation.

  • laziness is a disappointment. It promises performance gains, but those are so meager that they don’t make up for dealing with he unexpected behaviour of your code

  • homiconicity and lists: lists are rarely used in Clojure. I don’t understand why the language keeps them. Clojure forms are data, in particular: lists. If a data structure is representative of Clojure then its vectors or maps. Should Clojure be rewritten one day, then it would be better to use vectors for forms.

  • core.async is tough and there are too few books or articles that go into depth. Also, newcomers are sent to documentatiin written for golang.

  • Explanations often reference the hosting language, e.g. protocols. I don’t want to learn Java in order to learn Clojure.

2 Likes