Live data from Hacker News

Six Years of Professional Clojure

engineering.nanit.com

81–90 of 254 posts

Re: Six Years of Professional Clojure

#81
post #39

I started working professionally with Clojure earlier this year and this article rings true. I think the article leaves out a fourth downside to running on the JVM: cryptic stack traces. Clojure will often throw Java errors when you do something wrong in Clojure. It's a bit of a pain to reason about what part of your Clojure code this Java error relates to, especially when just starting out.

To be fair, this is not unique to Clojure. You need to deal with stack traces no matter what as long as you're using any programming language that targets the JVM (even statically type-checked languages like Scala). There are some great articles [1][2] that discuss various simple techniques helpful for debugging and dealing with stack traces.

[1] https://eli.thegreenplace.net/2017/notes-on-debugging-clojur...

[2] https://cognitect.com/blog/2017/6/5/repl-debugging-no-stackt...

Re: Six Years of Professional Clojure

#82
post #3

I found one of the perceived weaknesses of Clojure (in this article), it being dynamically typed, is a tradeoff rather than a pure negative. But it applies that tradeoff differently than dynamic languages I know otherwise and that difference is qualitative: It enables a truly interactive way of development that keeps your mind in the code, while it is running. This is why people get addicted to Lisp, Smalltalk and si…

The very first property testing library was written in Haskell, as far as I know.

Re: Six Years of Professional Clojure

#83

Earlier quoted context omitted.

Agreed. These days I'm really fascinated by clojure and trying to learn clojure. Other than the project setup and repl and the editor (which I had considered), these weird characters are throwing me off. What clojure really needs is some kind of opinionated framework or starter template, something like create-react-app. That has all these things figured out so a beginner like me can start playing with actual clojure,…

There is the widely used Luminus framework https://luminusweb.com/

Yes, of course and I've got the book as well. The problem with the book is I got stuck on the very first code example in the book. I know there's a forum for the book where (hopefully) I can get my query answered.

My point is: these are all individual attempts (the book i mean) and there will always be something on page xyz broken and it can't be solved by individuals. To solve these problems, there needs to be constant time and money investment from someone serious (like facebook in case of create-elm-app).

Re: Six Years of Professional Clojure

#84

Earlier quoted context omitted.

> What you get here goes way beyond what a strict, static type systems gets you, such as arbitrary predicate validation, Is this refinement types, which most static languages provide? https://en.wikipedia.org/wiki/Refinement_type > freely composable schemas, My understanding is that you can compose types (and objects) https://en.wikipedia.org/wiki/Object_composition I'm assuming that types are isomorphic with schemas…

>> Is this refinement types Well it does include that kind of behaviour but it's quite a bit more than just that. E.g. you could express something like "the parameter must be a date within the next 5 business days" - there's no static restriction. I'm not necesarily saying you should but just to give an illustrative example that there's less restrictions on your freedom to express what you need than in a static syste…

> E.g. you could express something like "the parameter must be a date within the next 5 business days" - there's no static restriction

Hm, I don't follow. If I were to write this in F#, there would be a type `Within5BusinessDays` with a private constructor that exposes one function/method `tryCreate` which returns a discriminated union: either an `Ok` of the `Within5BusinessDays` type, or an `Error` type with some error message. Once I have the type, I can then compose it with whatever and send it wherever and since F# records are immutable, I won't have to worry about invariants not holding. And since it's a type, I have the compiler/type system on my side to help with correctness.

(Side note, this is a bad example since the type can become invalid after literally 1 second... but since Clojure has the same problem I'm just running with it.)

I'm still learning Clojure (only a few months into it), but if I were to to write a spec, I'd have to specify what to do do if the spec failed to conform - same as returning the `Error` case in F#.

> i could swap out your spec for my spec so that would be 1:n but those specs may make sense to compose in other data use cases so really it's m:n rather than 1:1

Sorry, but I'm still not following - I believe you can do the same with types, especially if the type system support generics.

Re: Six Years of Professional Clojure

#86
post #31

Earlier quoted context omitted.

Usually the approach in a statically-typed language is to transform your dynamic request into something that you know through parsing instead of validation. Here's a great article about this: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... .

This is the second time I've seen the link above. And while I agree with the premise, the author clearly does not understand how to properly use the `Maybe` monad (a term that does not make an appearance!). There is little use in wrapping a call in `Maybe` to then immediately unwrap the result on the next line. Doing so isn't really using the construct... One would expect the lines following the creation of `Maybe` t…

I think you're referring to this part of the `getConfigurationDirectories` action, which has type `IO (NonEmpty FilePath)`:

    case nonEmpty configDirsList of
      Just nonEmptyConfigDirsList -> pure nonEmptyConfigDirsList
      Nothing -> throwIO $ userError "CONFIG_DIRS cannot be empty"
The "meaningful difference" you're looking for is the type of `getConfigurationDirectories`. The previous version had type `IO [FilePath] `, which _doesn't_ guarantee any configuration directories at all. It did indeed check the results and throw. But it doesn't guarantee that all the `[FilePath]` values in the program have been checked. There are neither tests nor proofs in this code. In contrast, with the revised version, you can be certain anywhere you see a `NonEmpty FilePath` it is indeed non-empty.

The code I've quoted that checks which case we have, is the only place that needs to handle that `Maybe`. Or maybe `main`, if we want to be more graceful. The author (I wouldn't say I know her but I know that much) does know how to chain maybes with bind but it's not necessary in this example code.

Re: Six Years of Professional Clojure

#87

> An incoming HTTP request? it is a plain Clojure dictionary. I learned to code in Python. Loved it. Dynamically typed dicts up the wazoo! Then I learned why I prefer actual types. Because then when I read code, I don't have to read the code that populates the dicts to understand what fields exist.

Question: 1. Can a GET request have a non-empty request body? 2. Assuming you don’t know the answer to that question, will the type system you use be able to tell you the answer to that question? This is a pretty simple constraint one might want (a constraint that only certain requests have a body) but already a lot of static type systems (e.g. the C type system) cannot express and check it. If you can express that c…

1. Yes. It's weird, but it's legal HTTP.

2. Sure. The request type has a body property.

Re: Six Years of Professional Clojure

#88
post #50
post #31

Earlier quoted context omitted.

Usually the approach in a statically-typed language is to transform your dynamic request into something that you know through parsing instead of validation. Here's a great article about this: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... .

That is a valid approach in any language. Static or not. Doesn't change my point that heavily. And it is all too possible to pick a bad parsing/binding language such that protocol changes in the request are now foot guns.

That's true, but static languages are not worse at handling dynamic data. From the same author: https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-typ....

Re: Six Years of Professional Clojure

#89

Earlier quoted context omitted.

Interesting. How exactly that looks? Do you have files opened in your editor, change them then go into previously opened repl, and just call the functions and the new version of those function runs?

That's right. You typically would have your text editor/ide open, and the process you're developing would expose a repl port which your editor can connect to. As you edit the source code, that will automatically update the code running in the process you're debugging. See this demo of developing a ClojureScript React Native mobile app published yesterday: https://youtu.be/3HxVMGaiZbc?t=1724

[deleted]

Re: Six Years of Professional Clojure

#90
post #18
post #9

Earlier quoted context omitted.

Nice! I missed it (or it didn't exist) when I last looked at Clojure a few years back

You missed it, it has been there forever. But it says good and bad things about Clojure that its reference documentation is one of its weakest points. The Guide/Reference split obscures a lot of information (do I want guidance on Deps & CLI or do I want reference on Deps & CLI?) and the guides where that gem is hidden randomly mix advanced topics (eg, how to set up generative testing), beginner topics (how to read Cl…

In my case it was even worse, as I started with ClojureScript, and official documentation was simply abysmal then.
Post reply on HN