11 ms·
Clojure – Fascinated, Disappointed, Astonished (2016)
- fiddlerwoaroof 7y agoThis post is pretty old and many of the things in the "disappointed" section have been improved quite a bit.
- akavel 7y agoEhhh; OP or mods, please add (2016) suffix...
- vimota 7y agoCurious about this! Could you elaborate on which?
- fiddlerwoaroof 7y agoMany of the points are error-message related and Clojure 1.9 and 1.10 have improved errors quite a bit
- Plugawy 7y agoAlmost nobody uses refs in production code ;-)
- AlexCoventry 7y agoThat was the case even before the blog post was written.
- goostavos 7y agoThey're also, in classic blog post form, disappointments after a whole two weeks with the language So, you have to know things like `let`, which means knowing the language, is strangely listed as a disappointment.
- capableweb 7y ago> I have to admit, that at the beginning using brackets was not easy for me. Once I’ve realized that the brackets are just on the other side of the function name, everything was simple and I could code very fast. Yeah, having automated insertion of brackets/parenthesis is necessary to adopt, otherwise you find yourself annoyed very quickly. Once you've adopted to automatic insertion of that, it's hard to go back to language where you don't have that...
- Swizec 7y agoThis is what drove me away from lisp. If everyone says you have to use a plugin to auto-insert parentheses, that means computers know where they go. So why are we writing them??
- azhenley 7y agoTry Forth :)
- wtetzner 7y agoThe computer only knows where they go because the rest of the code already has the parens. Having the parens has advantages, like everything being explicitly delimited, which makes it really unlikely that you'll insert some code that you thought was part of a block, but really wasn't (think one-armed if without braces in C-like languages). It also makes it easy to have your editor help you navigate your code. Being able to jump around expressions conveniently can really speed things up.
- Skunkleton 7y agoThe computer doesn’t know. It just knows that brackets need to go somewhere and makes it easier to edit them as a pair.
- mschaef 7y agoThey make the extent of syntactic expressions more obvious to both people and tools.
- capableweb 7y ago
- nickik 7y agoA couple of things to point out for new Clojure readers. The 'def' form should not be used inside of 'defn'. Local bindings should use 'let'. When using the STM, 'ref-set' should not be used most of the time. (def names (ref [])) (defn add-name [name] (dosync (alter names conj name))) The 'alter' function will call 'conj' and the return value will be the new value of 'names'.
- holtalanm 7y agoi was thinking that, too, while reading this. It has been a while since I wrote any Clojure, but I didn't remember ever using `ref-set` with STM. also, local bindings with `let` were the defacto standard.
- Scarbutt 7y agoWhen using STM, delete that code and start again without STM.
- bjoli 7y agoWhy should local bindings use let? In scheme internal (define ...) is defined in terms of letrec, which can add some overhead when letrec is unoptimized, but for schemes with optimized letrec (guile 3.0, chez, racket...) (define ...) is just as fast as let or let* unless you start doing cyclic references. The only real reason to not use Def would be if the bound symbol escapes the scope, but that would be ridiculous for a modern language.
- nickik 7y agoIn Clojure 'def' creates a 'var' and those are global in the namespace. > The only real reason to not use Def would be if the bound symbol escapes the scope, but that would be ridiculous for a modern language. Its not 'ridiculous' to have a consistent definition of what something does.
- pepper_sauce 7y agoIt does exactly what the documentation says it does: "Creates and interns or locates a global var with the name of symbol and a namespace of the value of the current namespace (ns)."
- Rapzid 7y agoBeen a while since I touched Clojure but at the time nothing beat light table's insta-REPL. Anything replace that, or any insta-REPL come close to replicating that experience for any language?
- giancarlostoro 7y agoThis is still my favorite way to do Clojure. I gotta say it's such a nice editor.
- nravic 7y agoJulia's REPL is beautiful
- BoiledCabbage 7y agoI never used LightTable, but based on the videos I've watched I believe the "Calva" plugin for VS Code has the same Clojure insta-REPL functionality. https://github.com/BetterThanTomorrow/calva https://github.com/BetterThanTomorrow/calva
- ledgerdev 7y agoThe integrated repl and inline results in lighttable were the best! Sad that it was abandoned. The best choice today for a similar experience is Chlorine(https://atom.io/packages/chlorine https://atom.io/packages/chlorine) which is built on top of Atom. It also uses the built in clojure socket repl, not the complex nrepl. Calva does it's best to show some data inline, but unfortunately vs-code doesn't support displaying inline results https://github.com/microsoft/vscode/issues/3220 https://github.com/microsoft/vscode/issues/3220
- BoiledCabbage 7y ago> Calva does it's best to show some data inline, but unfortunately vs-code doesn't support displaying inline results I've got no attachment to the Calva project whatsoever, but the below link pretty clearly contradicts what you're claiming. https://calva.readthedocs.io/en/latest/eval-tips.html#evaluation-in-a-file-editor https://calva.readthedocs.io/en/latest/eval-tips.html#evalua... Not to mention I've done it.
- kotutku 7y ago> I have to admit, that at the beginning using brackets was not easy for me. Once I’ve realized that the brackets are just on the other side of the function name, everything was simple and I could code very fast. A question to fellow Lispers: is there a good reason why LISPs do not put parenthesis they way we know from math? Why `(f foo bar)` and not `f(foo bar)`?
- pdonis 7y ago> is there a good reason why LISPs do not put parenthesis they way we know from math? Why `(f foo bar)` and not `f(foo bar)`? Because the first is a list and the second isn't. The whole point of LISP is to represent code as data, and the fundamental data structure it uses is a list.
- MadWombat 7y agowell... (1 2 3) is syntactic sugar for (cons 1 (cons 2 (cons 3 nil))). What prevents someone from adding syntactic sugar f (x y) for (f x y)?
- dunefox 7y agoThe fact that one of these is a list of symbols and the other one isn't. They mean different things.
- MadWombat 7y ago> "They mean different things" For fuck's sake, these things don't mean anything by themselves. The only reason they mean different things is because the syntax is defined this way. So back to the original question, why is the syntax defined this way?
- deleted 7y ago[deleted]
- gsk22 7y ago
- bcrosby95 7y agoIt's missing my favorite concurrency construct: immutable, persistent data structures. I was initially interest in Clojure for things like STM, but found most of my concurrency problems are amenable to immutable data. You can certainly use this technique in other languages, but it tends to be higher effort.
- kubanczyk 7y agoNo. Immutable structures still require locking. If you are spending 100 ms calculating the new version of the immutable structure, you want to make sure that the nearby thread isn't making their own version. You don't want any of the two results silently overwritten. You want the nearby thread be sequential - to wait for you and base on your result.
- Scarbutt 7y agoIf he's talking about multithreading he probably wanted to say immutable data structures in combination with clojure's atom (CAS semantics).
- deleted 7y ago[deleted]
- dpratt71 7y agoThis is not how persistent data structures are used in practice. There is no "the" new version of a persistent structure. The best analogy I can think of is to compare it to a VCS (e.g. git). There is no need to lock any existing commit in order to create a new commit (which together with prior commits, represents a new version of the code).
- majormajor 7y agoI'm not familiar with Clojure, but you can hit conflicts in the Git world, though, which seem to be what the parent is concerned about. Two of us could be creating some new data based on the last data we had, at time T, and then the other person submits theirs at time T+5, and I submit mine at time T+10. In that case, my change hasn't taken theirs into account.
- dwohnitmok 7y agoJust so people don't get the wrong idea, AFAICT STM isn't used that much in production Clojure (unlike say Haskell). This I chalk up to the lack of a couple crucial operators in Clojure's STM. Instead the usual method for dealing with concurrency is atoms. Note that once you get familiar with how to use atoms to structure concurrency, this is a lesson that is widely applicable. You can, for example, write essentially the same code in Java with an AtomicReference (how atoms are implemented anyways) as long as you take care to only put immutable data structures in the ref. I would personally sum up Clojure's main impact on my own programming in two ways. 1. 90% of the time you just need immutable maps, sets, vectors, and primitives. Fancy custom classes and custom higher order functions usually aren't needed. 2. Wishing more things had on-the-fly editing of a running program.
- arohner 7y agoIn my experience, STM isn't used because it's very rare to have situations where you need STM but don't need durability. In most production situations, you need to record state changes in a DB or an event log. In that case, the source of truth is now the DB, and your in-memory values are immutable snapshots. The other reason is that Clojure code is usually well-factored, and most clojurians have listened to Rich and simplified their programs. Not many problems require STM transactions across multiple refs. If you don't have multiple refs changing transactionally, you can use atoms instead for a performance benefit.
- the-alchemist 7y agoI came from a strict C++ -> Java/Python world. My college class on programming languages included a Lisp, I think, but that was so long ago and was so poorly taught that I graduated without ever hearing the word "REPL". So grokking, let alone writing, Clojure code was daunting but extremely worthwhile. All good things come to those who wait, and sure enough, I see it now. Massive gain in productivity. Like, probably more than going from C++ to Java, or Java to Python (for me). P.S. This article is definitely a little dated in parts, but has of the warts still stand.