HN user

uDontKnowMe

303 karma
Posts0
Comments65
View on HN
No posts found.

I'm not so sure. I wish it were as you say but there are currently 5600 job postings mentioning Scala on LinkedIn in the USA, vs 82 that mention Clojure. 82! In the entire USA. So even in its state of relative decline, Scala might be about 70 times as used in industry as Clojure is.

Even as I flip through the 7 postings mentioning Clojure in all of Canada, only 4 of them seem to indicate the job itself makes use of the language (rather than mentioning it just as an example language as in "* Fluency in one or more languages like Ruby, Clojure, Scala, ReactJS, JavaScript, TypeScript, Java, Python - Deep understanding of internet protocols and standards.")

It's interesting you call relationships on Reddit para-social, I don't know if that quite fits the word because Reddit is more of a two-way reciprocal relationship between commenters. Perhaps Twitter fits that description better since you get a lot of power users like Trump and other celebrities which broadcast out to their followers but don't typically respond to normies.

Unfortunately even if you only cared about plants, you would still be better off on a vegan diet because animal agriculture requires order(s) of magnitude more plants to be cultivated than a vegan diet would, on account of it taking many calories of plant feed to produce a calorie of meat.

The food chain is an abstraction that describes the natural world, not a moral agent any more than the water cycle is. Wild animals predate in the wild, yes, but they aren't moral agents. Humans are able to reason about our own actions and more importantly we can live and indeed thrive on a plant-based diet. So since there are ways to get our food other than killing other thinking, feeling, suffering individuals, we aren't forced to do so. We just choose to inflict incomprehensible amounts of suffering on animals not out of necessity but because we like the taste of cow milk slightly more than we like the taste of oat milk, or we love the way their flesh tastes, and would rather eat it than cook a plant-based meal.

We inflict billions of lifetimes of misery and torture on creatures with their own desires and will to live, who feel suffering and pain just as much as we do, in service of an utterly unnecessary and trivial benefit, that while we could live incredibly well, even healthier and with less impact on the environment on a plant-based diet, we like the taste of their flesh and excretions too much to choose oat milk and tofu at the grocery store.

Yes it is wrong! Future generations will look back at our time as with disbelief that we behave like this.

I explored this briefly but it ended up taking about 25 seconds to compile hello-world in Clojure. That struck me as causing a lot of pain to develop for.

That, combined with how you'd lose access to a lot of the java library ecosystem, makes it less appealing to me to develop on.

What do you mean by democratic? Are you thinking of some kind of election system to replace mods, and if so have you seen such a mechanism work anywhere else on forums?

I think it's a common misconception that old.reddit.com is still extremely popular. As a mod of a medium-large sub which should skew highly towards old.reddit.com (developer-focussed content, created at around the beginning of reddit itself), the percent of pageviews on old.reddit.com is right now around 8%.

Exactly, and all you need is Any

If you're using Any, then your program is (at least in part) dynamically typed. I don't think it's fair to say "look! Static typing is better than dynamic typing in any and all situations! (so long as it can use dynamic typing)"

That's true! But now we'll get into what is possible vs what is idiomatic, common, and supported by the language/stdlib/tooling/libraries/community. If I remember correctly, Rich Hickey did actually do some development for the US census, programming sort of in a Clojure way but in C#, before creating Clojure. But it just looked so alien and was so high-friction that he ended up just creating Clojure. As the article I linked to points out, "at some point, you're just re-implementing Clojure". That being said, it's definitely possible, I just have almost never seen anyone program like that in Java/Scala.

I've seen this article and I applaud it for addressing the issue thoroughly but I still am not convinced that static typing as we know it is as flexible and generic as dynamic typing. Let's go at this from an other angle, with a thought experiment. I hope you won't find it sarcastic or patronizing, just trying to draw an analogy here.

So, in statically typed languages, it is not idiomatic to pass around heterogeneous dynamic maps, at least in application code, like it is in Ruby/Clojure/etc. But one analogy we can draw which could drive some intuition for static typing enthusiasts is to forget about objects and consider lists. It is perfectly familiar to Scala/Java/C# programmers to pass around Lists, even though they're highly dynamic. So now think about what programming would be like if we didn't have dynamic lists, and instead whenever you wanted to build a collection, you had to go through the same rigamarole that you have to when defining a new User/Record/Tags object.

So instead of being able to use fully general `List` objects, when you want to create a list, that will be its own custom type. So instead of

  val list = List(1,2,3,4)
you'll have to do:
    case class List4(_0: Int, _1: Int, _2: Int, _3: Int)
    val list = List4(1,2,3,4)
This represents what we're trying to do much more accurately and type-safely than with dynamic Lists, but what is the cost? We can't append to the list, we can't `.map(...)` the list, we can't take the sum of the list. Well, actually we can!
    case class List5(_0: Int, _1: Int, _2: Int, _3: Int, _4)
    def append(list4: List4, elem: Int): List5 = List5(list4._0, list4._1, list4._2, list4._3, elem)
    def map(list4: List4, f: Int => Int): List4 = List4(f(list4._0), f(list4._1), f(list4._2), f(list4._3))
    def sum(list4: List4): Int = list4._0 + list4._1 + list4._2 + list4._3
So what's the problem? I've shown that the statically defined list is can handle the cases that I initially thought were missing. In fact, for any such operation you are missing from the dynamic list implementation, I can come up with a static version which will be much more type safe and more explicit on what it expects and what it returns.

I think it's obvious what is missing, it's that all this code is way too specific, you can't reuse any code from List4 in List5, and just a whole host of other problems. Well, this is pretty much exactly the same kinds of problems that you run into with static typing when you're applying it to domain objects like User/Record/Car. It's just that we're very used to these limitations, so it never really occurs to us what kind of cost we're paying for the guarantees we're getting.

That's not to say dynamic typing is right and static typing is wrong, but I do think that there really are significant costs to static typing and people don't think about it.

Not who you are responding to, but the common idea that static types are all win and no cost has become very popular these days, but isn't true, it's just that the benefits of static typing are immediately apparent and obvious, but their costs are more diffuse and less obvious. I thought this was a pretty good write up on the subject that gets at a few of the benefits https://lispcast.com/clojure-and-types/

Just to name some of the costs of static types briefly:

* they are very blunt -- they will forbid many perfectly valid programs just on the basis that you haven't fit your program into the type system's view of how to encode invariants. So in a static typing language you are always to greater or lesser extent modifying your code away from how you could have naturally expressed the functionality towards helping the compiler understand it.

* Sometimes this is not such a big change from how you'd otherwise write, but other times the challenge of writing some code could be virtually completely in the problem of how to express your invariants within the type system, and it becomes an obsession/game. I've seen this run rampant in the Scala world where the complexity of code reaches the level of satire.

* Everything you encode via static types is something that you would actually have to change your code to allow it to change. Maybe this seems obvious, but it has big implications against how coupled and fragile your code is. Consider in Scala you're parsing a document into a static type like.

    case class Record(
      id: Long,
      name: String,
      createTs: Instant,
      tags: Tags,
    } 
    
    case class Tags(
      maker: Option[String],
      category: Option[Category],
      source: Option[Source],
    )
//...

In this example, what happens if there are new fields on Records or Tags? Our program can't "pass through" this data from one end to an other without knowing about it and updating the code to reflect these changes. What if there's a new Tag added? That's a refactor+redeploy. What if the Category tag adds a new field? refactor+redeply. In a language as open and flexible as Clojure, this information can pass through your application without issue. Clojure programs are able to be less fragile and coupled because of this.

* Using dynamic maps to represent data allows you to program generically and allows for better code reuse, again in a less coupled way than you would be able to easily achieve in static types. Consider for instance how you would do something like `(select-keys record [:id :create-ts])` in Scala. You'd have to hand-code that implementation for every kind of object you want to use it on. What about something like updating all updatable fields of an object? Again you'll have to hardcode that for all objects in scala like

    case class UpdatableRecordFields(name: Option[String], tags: Option[Tags]) 
    def update(r: Record, updatableFields: UpdatableRecordFields) = {
      var result = r
      updatableFields.name.foreach(r = r.copy(name = _))
      updatableFields.tags.foreach(r = r.copy(tags = _))
      result
    }
all this is specific code and not reusable! In clojure, you can solve this for once and for all!
    (defn update [{:keys [prev-obj new-obj updatable-fields}]
      (merge obj (select-keys new-fields updatable-fields)))
    
    (update 
      {:prev-obj {:id 1 :name "ross" :createTs (now) :tags {:category "Toys"}} 
       :new-obj {:name "rachel"} 
       :updatable-fields [:name :tags]})
      => {:id 1 :name "rachel" :createTs (now) :tags {:category "Toys"}}  

I think Rich Hickey made this point really well in this funny rant https://youtu.be/aSEQfqNYNAc.

Anyways I could go on but have to get back to work, cheers!

Yes I agree there is a problem of a lack of institutional funding in the Clojure world. Luminus is a great tool but it is a bit sad that it is arguably the most production-ready web toolkit in the ecosystem and it is mostly the work of a single person.

There is some community effort to better fund the core infrastructure in Clojure through https://www.clojuriststogether.org/, hopefully they can continue to attract more funding developers and companies.

In general a lot of these issues could be alleviated if the community was just in general larger with more contributors. I think the Clojure community is quite welcoming to newbies in the sense that people are quite responsive, kind and helpful around the internet, in Clojurians Slack (try asking there btw, if you haven't yet and are still stuck at the start of the book), etc. But in other ways people seem averse to criticism or suggestions from outsiders. I think the Clojure world needs to do a bit of self reflection to understand why adoption is so low right now and honestly consider what needs to change to attract more developers and contributors.

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

Thanks for that great series! It reminded me a lot of this demo for O'Doyle Rules, a Clojure rules engine library, wherein the author demos a dungeon crawler style video game written top to bottom using only the rules engine for logic https://youtu.be/XONRaJJAhpA?t=1577

He also goes on to show a text editor written entirely in the rules engine (which he uses to develop the game in), really cool stuff!

This is way old ancient irrelevant news as the project never really took off and was quickly abandoned/contributors refocussed on Scala proper. That was also many major versions of Scala ago (2.11, which has since been succeeded by 2.12, 2.13, and now 3.0). No idea why this would be submitted in 2021.

I don't think this is universally true, no. Historically there have been large migrations of developers from traditional statically typed languages towards Ruby/Python/JS/Groovy/Clojure. In fact, Clojure was designed by and is used by well experienced developers fed up with the added complexity of type systems.

I like:

Defn: https://podtail.com/en/podcast/defn/

The REPL: https://www.therepl.net/episodes/ (Seems to have gone quiet)

ClojureScript Podcast: https://clojurescriptpodcast.com/

Functional Design in Clojure: https://clojuredesign.club/ (Also seems to have gone quiet since December)

LispCast by Eric Normand: https://lispcast.com/

Cognitect, the company behind Clojure also has their own podcast but I haven't found it to be that interesting most of the time, at least yet: https://www.cognitect.com/cognicast/index.html

Not specifically Clojure-related but has discussed a few times including wit Rich Hickey (as well as other unrelated great conversations!): CaSe https://www.case-podcast.org/

Completely not at all about Clojure but great software podcasts:

Go Time: Even though I hardly ever write Go, I find their conversations to be really great and having lessons beyond Go. It helps that I am interested in the language though: https://changelog.com/gotime

Web Development and Development in general - The Bike Shed: https://www.bikeshed.fm/

Software Engineering Radio: https://www.se-radio.net/

CoRecursive: https://corecursive.com/

Inside Java: https://inside.java/