Live data from Hacker News

Six years of professional Clojure development

falkoriemenschneider.de

171–180 of 209 posts

Re: Six years of professional Clojure development

#171

Earlier quoted context omitted.

Curious, because I'm also doing Scheme now, and Clojure was my gateway drug, which Scheme are you using and for what sort of problem? I'm using s7, but that's because my use case is very much oriented to s7's non-typical feature set (it's computer music), but Janet looks really nice too. (Many similarities to both Clojure and s7 actually).

Interesting, Clojure was my gateway drug to CL. I wonder how common it is for people who come to Clojure but get warned off by the JVM to migrate further down the lisp road?

yeah that was basically it for me. JVM for computer music just doesn't make any sense but I loved the language so went hunting for others.

Re: Six years of professional Clojure development

#172

Clojure is the most enjoyable language I've ever used and I love the interactive development. I haven't written code in any other language that even comes close. Unfortunately I am too lazy and careless to use Clojure in any serious capacity though. I really need a Haskell or Rust compiler to remind me of all my silly mistakes. I can't be trusted to get to the same level of confidence through unit tests or linting or…

I've been using Clojure since the summer of 2009, started a startup with it, using it exclusively on one project right now... and I agree about static types. I love many many things about Clojure, its my favourite language to use and I find it very well designed over all. But proper first class static types are the one thing I wish it had. My dream programming language is basically a statically typed Clojure. I've on…

Do you know about the Typed Clojure project? More or less Racket's contract system, for Clojure:

https://github.com/clojure/core.typed

To me, it's one of the great testaments to the power of Lisp that you can bolt on a static type system after the fact.

Re: Six years of professional Clojure development

#173

Earlier quoted context omitted.

Line breaks only shorten lines, they do not change the reading direction. Yes, you can start at the bottom and read upwards, but that's unnatural for most. Compare: something.first().second().third() With: (third (second (first (something)))) The end from read must you to understand, and it gets more complicated as your code does. No wonder Clojure's threading macro is so popular, as it would allow you to write it as…

You have a strawman example of piping via .member() because those () sometimes have arguments; that's what they are there for. Function application has not gone away; it's just combined with obj.member access. It can easily become an unreadable mess that will need some way of splitting across lines and indenting: something.first(other.foo(bar.f(x, y)).memb, z).second(x.y()).third(a, b, c) This: (third (second (first…

Of course you could work around s-expressions (and make your ALGOL-formatted language looks like Lisp, a common complaint against my own code by my coworkers), that wasn't my argument.

Most aren't fond of Lisp syntax, regardless of how you dress it up, and thus writing in Lisps doom you to have fewer people to hand over your code to, and I don't think that scarcity is useful. I suspect the reason most don't like s-expression is that it forces the human reader to maintain a "mental stack", an exercise humans are not too good at, as demonstrated by human languages aversion of center embeddings.

Re: Six years of professional Clojure development

#174

Earlier quoted context omitted.

I've been using Clojure since the summer of 2009, started a startup with it, using it exclusively on one project right now... and I agree about static types. I love many many things about Clojure, its my favourite language to use and I find it very well designed over all. But proper first class static types are the one thing I wish it had. My dream programming language is basically a statically typed Clojure. I've on…

Do you know about the Typed Clojure project? More or less Racket's contract system, for Clojure: https://github.com/clojure/core.typed To me, it's one of the great testaments to the power of Lisp that you can bolt on a static type system after the fact.

Yes, but it’s really not the same as first class static typing support. It also doesn’t help when none of the libraries you use have type annotations and when I last looked it was also quite slow.

Re: Six years of professional Clojure development

#175

Earlier quoted context omitted.

That's true if you write everything on one line. But how could you fail to notice that most Lisp code is written on multiple lines and indented? The structure is visually laid out, so as not to be maintained in anyone's head.

Line breaks only shorten lines, they do not change the reading direction. Yes, you can start at the bottom and read upwards, but that's unnatural for most. Compare: something.first().second().third() With: (third (second (first (something)))) The end from read must you to understand, and it gets more complicated as your code does. No wonder Clojure's threading macro is so popular, as it would allow you to write it as…

> Lisp was never supposed to be written with S-expressions. They were intermediate representation, for bootstrapping.

That's not the complete picture.

The early Lisp manual had a definition for Lisp syntax. The Lisp syntax was based on M-expressions for code and S-expressions for data.

Basically what now is

    (append (quote (1 2 3))
            (quote (a b c)))
was

    append[(1,2,3);(A,B,C)]
where the function call uses M-Expression syntax and the data were S-expressions.

Then we have so-called S-Functions, which work with S-expressions. append is such an s-function.

McCarthy then defined a mapping from M-Expressions to S-Expressions, thus that M-Expressions could be represented (not just written, but also in memory) as S-expressions.

In the next step he defined new S-functions called apply and eval, which took M-Expressions as S-Expression data and computed the results of apply or eval operations.

Example use of apply:

   apply[(LAMBDA,(X,Y),(CONS,X,Y));((A,B),(B,C))]
Thus these s-functions could compute with code which was represented at runtime by s-expression data.

Thus such a program would use both code in M-Expression format and compute with code in S-Expression format.

Since these S-functions apply and eval could be themselves translated to s-expressions and get executed, the specific S-functions apply and eval could get executed by a s-expression evaluator.

The code above would then be written:

    (APPLY,(LAMBDA,(X,Y),(CONS,X,Y)),(QUOTE,((A,B),(B,C))))
which in modern way would be written as

    (apply (lambda (x y)
             (cons x y))
           (quote ((a b) (b c))))
Since programs thus were executed / computed as s-expressions, they were input, computed and printed as s-expressions.

Thus the idea of a simple s-expression meta-programming system made the idea of an additional step of m-expression syntax reading/printing less attractive.

Re: Six years of professional Clojure development

#176

Earlier quoted context omitted.

> Do you really want a dynamic language, or do you just want the ability to be careless intermittently? [...] I just think, as a codebase in a dynamic language grows, codebases seem to build lots of tooling to make that dynamic language less dynamic. I think this is getting closer to the interesting questions. It's often a good thing that when the product matures and moves more into maintenance mode, you can then inc…

Yeah, it seems like programming language decision is, at least in part, a proxy for "At what point do you want to be held accountable for your program's correctness at runtime?" Haskell/Rust - Immediately Java/C#/Go - Relatively quickly Dynamic Languages - Whenever you decide it becomes important

Whether you get strong assurance of correctness from static typing depends on your domain, are you're working with a closed-world app like a compiler, or a talking to the rest of the world a lot?

Though it's telling how little static checking by type systems is leveraged eg in LLVM, so even in closed systems the assurance payoff for static checking doesn't necessarily get good bang for the buck.

Eg working with web based services, your code tends to communicate a lot with other services, and a very large % of bugs that make it further out than your dev laptop come from those interfaces. Making these part of the closed world of the static type system is done in some places but most static language users elect not to do it, preferring programmable checks in form of schemas or tests. Which I think tells something.

I tend to think of static vs dynamic as a mindset question, where our bias of loss aversion rears its head. It's an attractive idea to hedge your risks by usign a static language even if it only catches the trivial bugs and slows you down, because statically found bugs are a falsifiable observation, wheras making programming easier, faster and more fun[1] in general doesn't leave hard evidence unless you run duplicate trial projects just for science.

[1] For some personalities, you might derive more fun and satisfaction in the mathematical certainty of static languages. Or you might be in a work environment where you don't have room to find fun anyway. Or maybe you don't even like programming. Yet others find fun indispensable: fun is necessary for keeping up morale.

Re: Six years of professional Clojure development

#177

Earlier quoted context omitted.

> Do you really want a dynamic language, or do you just want the ability to be careless intermittently? [...] I just think, as a codebase in a dynamic language grows, codebases seem to build lots of tooling to make that dynamic language less dynamic. I think this is getting closer to the interesting questions. It's often a good thing that when the product matures and moves more into maintenance mode, you can then inc…

Yeah, it seems like programming language decision is, at least in part, a proxy for "At what point do you want to be held accountable for your program's correctness at runtime?" Haskell/Rust - Immediately Java/C#/Go - Relatively quickly Dynamic Languages - Whenever you decide it becomes important

It's a bit of an oversimplification, I think.

Even though Clojure is not a statically typed language, it does have a type system.

Here's an example what Clojure.Spec lets you do. When I was working for a fintech company, we built a suite of specs for a ledger. Based on those specs we could generate data. And it wasn't just some set of key/value pairs with completely randomized numbers. It would generate "a proper" ledger, where every number in a transaction depends on other transactions.

We used that generated data to render UI locally and on the non-prod environments.

Using the same specs we build data validators, we re-used the specs to validate data in the input fields in the UI. Which is totally bonkers. How the heck you achieve code re-use between completely incompatible ecosystems - in our case, JVM and Javascript? Even Nodejs doesn't always let you re-use code between backend and the front. Clojure allows you.

Using the same specs, we've built property based/generative tests.

I've never experienced the joy of creating such robust, predictable, and reliable software with any other (statically typed or otherwise) language before.

I'm not saying you cannot build a similar thing (or even better) with Scala or Haskell (or some other PL). The simplicity of how Clojure allows you to write things like that - just incomparable.

Re: Six years of professional Clojure development

#178
post #147

Earlier quoted context omitted.

> Unfortunately I am too lazy and careless to use Clojure in any serious capacity though. I really need a Haskell or Rust compiler to remind me of all my silly mistakes. I can't be trusted to get to the same level of confidence through unit tests or linting or spec or malli. I think most developers cannot be trusted to make these mistakes, I wouldn't call it "careless or lazy". Languages exist with tools baked into t…

> Do you really want a dynamic language, or do you just want the ability to be careless intermittently? [...] I just think, as a codebase in a dynamic language grows, codebases seem to build lots of tooling to make that dynamic language less dynamic. I think this is getting closer to the interesting questions. It's often a good thing that when the product matures and moves more into maintenance mode, you can then inc…

> If you had a rigid system and slow turnaround from the start, you might not have gotten off the ground to get that far.

I always see people say this and on the surface it seems to make sense, but I also always wonder what "rigid system" they're talking about. It's much, much faster to make big changes in every phase of a project in Haskell for me than it is in Elixir, so this is the perspective I'm seeing this from. This hypothetical/straw man "rigid system" is hard to fathom.

Re: Six years of professional Clojure development

#179

Earlier quoted context omitted.

Yeah, it seems like programming language decision is, at least in part, a proxy for "At what point do you want to be held accountable for your program's correctness at runtime?" Haskell/Rust - Immediately Java/C#/Go - Relatively quickly Dynamic Languages - Whenever you decide it becomes important

Whether you get strong assurance of correctness from static typing depends on your domain, are you're working with a closed-world app like a compiler, or a talking to the rest of the world a lot? Though it's telling how little static checking by type systems is leveraged eg in LLVM, so even in closed systems the assurance payoff for static checking doesn't necessarily get good bang for the buck. Eg working with web b…

I don't particularly want to argue with you. Using the phrase "falsifiable observation", and then referencing "fun" as an argument just doesn't really work for me. I appreciate that you like dynamic languages, but I will not take your "rest of the world" bait. To suggest that dynamic typesystems are as verifiably correct as static typesystems is verifiably incorrect.

Re: Six years of professional Clojure development

#180
post #95

I've used Clojure for going on 10 years now and it has been one of the most enjoyable programming languages I've ever used. But I've gone back to Scheme for a few ridiculous reasons. 1. TCO. Using `recur` in Clojure just breaks my thought process. 2. Difficulty in getting down to the metal when needed. Using JNI is painful. In Scheme, when needed, the FFI usually handles plain old C. Much easier in my opinion. 3. Com…

I don't understand arguments of the kind: "Lisp A vs. Lisp B". A Lisp is a Lisp. I am honestly so grateful for my younger self for the decision I made years ago to learn Lisp. These days, pretty much any platform, any hardware, or a VM supports at least one dialect of Lisp. And that's awesome!

I switch between Lisps with relative ease: Scheme, Fennel, Clojure, Elisp, Common Lisp - they feel pretty much the same language. Yes, each has its own oddities and quirks, but I still feel like if I'd discovered some ancient secret - learn it and you start understanding every possible human language. That's how knowing and "breathing" Lisp feels sometimes.

Because Lisp is not a language. It's an idea. An incredibly awesome one. Arguably - the most influential idea in Computer Science. "Once in a millennia" idea.

That's why I never feel anxious about the popularity of programming languages. I don't care what's in the top of RedMonk or TIOBE or whatever else. I don't care if some new programming language gets promoted by the Queen of England, Supreme Pontiff, or Dalai Lama. If it's not a Lisp - it has an expiration date. Lisp, though, will never die.

Post reply on HN