Live data from Hacker News

My Increasing Frustration with Clojure

ashtonkemerling.com

231–240 of 240 posts

Re: My Increasing Frustration with Clojure

#231

Earlier quoted context omitted.

cljs.user=> (source clojure.set/union) (defn union "Return a set that is the union of the input sets" ([] #{}) ([s1] s1) ([s1 s2] (if ( (source clojure.set/intersection) (defn intersection "Return a set that is the intersection of the input sets" ([s1] s1) ([s1 s2] (if (

I don't feel that I know any more now than I did before you posted this "reply". The third branch ([s1 s2]) adds the elements of the smaller collection one by one onto the larger collection. Conceptually, it does this by constructing a new copy of the result for every addition, since conj is not destructive. It is buggy and will return a result of whatever type the larger collection is, with data being duplicated if…

> Conceptually, it does this by constructing a new copy of the result for every addition, since conj is not destructive

That's not how persistent data structures work

http://hypirion.com/musings/understanding-persistent-vector-...

> why does efficient set union of two collections require one of the two collections to support fast membership tests

I haven't thought much about this but it seems intuitively true to me. You want to take the smaller set, and add each item to the larger set if it doesn't already exist. That last part is why you need a fast membership test.

If you're still unconvinced, try loading up two similarly structured database tables with a million rows and get the union of them (with and without indices). The indexed one will be orders of magnitude quicker.

Re: My Increasing Frustration with Clojure

#232
post #46

Odd, in two years I've never been bit by a single one of these bugs. And if I had, I could probably pretty easily shrug them off. My frustration came from the lack of a type system, and that there's no "myThing." (myThing-dot) to give you intellisense. Even many dynamic language editors have some variant of this now. So coding in Clojure involves too much looking stuff up and memorizing stuff, and is way slower than…

What editor do you use? Emacs Cider does this, and does it much better than IDEs (IMO).

I use Cursive, and yes it has intellisense equivalent to Cider, but still not good enough.

In Scala, Java, C#, F#, C++, I can do `myArray.` and it shows all methods available to arrays. No Clojure editor has anything like this. JetBrains editors take it a step farther and even include "code template" options that apply. So typing "myArray." will also include options for "foreach, for, for-reverse" templates. This, in addition to automatically importing any required library for the method you select.

With Clojure, there's no "dot". You're stuck hunting through documentation, trying to figure out first which namespace your function belongs to, then requiring it, then figuring out which function you want. Cursive only helps out with that last step, and even then, it displays every function in the namespace, when generally you only want to see the functions that apply to your variable.

While I'm all about immutability and structured data types, I've grown slightly away from functional-first languages in general for that reason. Even in F#, you've got to do `myList |> List.map ... |> List.filter ...` etc, requiring more lookup than C#'s `myList.Select(...).Where(...)`. The "dot" is an underappreciated aspect of OOP.

Re: My Increasing Frustration with Clojure

#233

Earlier quoted context omitted.

Could you elaborate why? (Haven't done much C) - Is the point of view that it is the languages job to prevent the programmer from relying on uncertainties?

The C standards take the rather unique approach of dividing behavior into 4 categories: * standard-defined . You can rely on this; if the code you write is limited to this, you're good to go. * erroneous . The compiler is supposed to give you an error message when you write code like this. * implementation-defined . A particular compiler can do something reasonable with the code. If you write code depending on implem…

I had an itch in my mind that some rigor was lacking in his analysis as I was reading the blog post, and this captures it much better than I could have. My model has always been that methods should have well-defined behavior when the input satisfies preconditions, but may or may not error when input does not satisfy preconditions (i.e. the response could simply be undefined, rather than raising an error).

This taxonomy is much more comprehensive, and you've laid it out well. Thanks.

Re: My Increasing Frustration with Clojure

#234

Earlier quoted context omitted.

Thank you. The only problem here would probaby only be the lack of clear and strong statements about the Clojure philosophy. The C standard for example clearly shows the areas where there is an undefined behaviour and when you can expect the "garbage in, garbage out" behaviour. Is Clojure doing the same? As a relatively mature man and a programmer for me the way a project is maintained is just as important as the abi…

You'll only be shamed (by me) if you go write a long blog post complaining about it. I don't represent the entire community. Otherwise, you'll be politely corrected and have the tradeoffs explained to you in IRC or Slack. My apologies if I've given you any other impression.

Thank you again. No, you didn't give me that impression. The author gave me the impression that this is the predominant answer he was given -- or he assumed so.

I have zero idea if that's the case, though. I'd be glad to work with a technology if I had a polite and constructive person such as yourself to help me out when I am really stuck.

Re: My Increasing Frustration with Clojure

#235

Clojure is a language for people who know what they are doing by people who know what they are doing. If you're giving sequences to the set functions, you either (A) don't know what you're doing or (B) have yet to discover that clojure.set is not what you want. Set union can't be done efficiently on arbitrarily sized sequences. At least one of the two arguments needs to offer fast set membership; ideally the larger o…

As someone who is unfamiliar with clojure -- is there any particular reason a function which doesn't actually work with sets allows non-sets to be passed to it in the first place? Or this a deficiency in the type-checking? I mean, truly, this kind of thing seems like a solved problem...

Re: My Increasing Frustration with Clojure

#236
post #235

Clojure is a language for people who know what they are doing by people who know what they are doing. If you're giving sequences to the set functions, you either (A) don't know what you're doing or (B) have yet to discover that clojure.set is not what you want. Set union can't be done efficiently on arbitrarily sized sequences. At least one of the two arguments needs to offer fast set membership; ideally the larger o…

As someone who is unfamiliar with clojure -- is there any particular reason a function which doesn't actually work with sets allows non-sets to be passed to it in the first place? Or this a deficiency in the type-checking? I mean, truly, this kind of thing seems like a solved problem...

This is a tradeoff made with dynamically-typed languages. Open up your dev console and try some JS for other examples: `[] + []` or `[] + {}` or `{} + []` or `{} + {}`.

There are several ways to solve it all with tradeoffs. Types can solve it with tradeoffs. Checking the types in the function can solve it with tradeoffs. Stating in the docs what arguments may be passed is another way to solve it.

Re: My Increasing Frustration with Clojure

#237
post #96

Earlier quoted context omitted.

By removing the server-side layer I mean, for example, moving the "model" logic in MVC to the client. The database is still there, but it doesn't perform any application logic, so the server-side layer is moved to the client, not the database. The challenge then becomes authorization. Ideally even the database would be ad-hoc distributed yet would maintain authorization functions or at least the practical result of t…

You still need to do all the same things as before. Some things you move to the client, other things you move to the dbms. There isn't some functionality that magically disappears when you no longer have, for example, a PHP/Ruby/Python/JS/whatever server mediating between your client and your database.

The object-relational impedance mismatch disappears when the dbms is an immutable time series, which means a whole bunch of plumbing code does indeed evaporate

Re: My Increasing Frustration with Clojure

#238

As a dev programming in Clojure professionally day to day this complaint (core team not fixing/prioritizing bugs) seems absurd to me. The only example given for a bug is not even a bug but undefined behavior triggered by undocumented API usage. If the author means clojure.spec by "greenfield development" (I don't see what else he could mean) he should really reconsider his complaint since clojure.spec is going to do…

If the author means clojure.spec by "greenfield development" (I don't see what else he could mean)

EDN, Transit, reducers, transducers, clojure.spec

(I'm not saying any of these things are bad or anything, just pointing out that there was a lot of green field development done in the past few releases)

Re: My Increasing Frustration with Clojure

#239
post #224

Earlier quoted context omitted.

You still need to do all the same things as before. Some things you move to the client, other things you move to the dbms. There isn't some functionality that magically disappears when you no longer have, for example, a PHP/Ruby/Python/JS/whatever server mediating between your client and your database.

My proposal is that almost nothing moves to the dbms, everything moves to the client except perhaps authorization. Unfortunately I can't fully defend my line of reasoning without saying, here's a link to my fully described or developed alternative architecture, which I don't have. However that doesn't mean it's not possible, it seems to me to be achievable. Even if it would require changes to HTTP, the database (row,…

> I imagine it would be much easier to reason about an application that is data and data authorization on one side, and logic on the other.

You're basically describing, for example, a Ember/Android/iOS + Rails + Postgres app. Logic lives in the client (Ember/Android/iOS). Data + Authorization lives in Rails + Postgres. And the Rails part of that is really not doing much. It's deciding if a request is allowed, then serializing or deserializing data from the database. I guess you can do that in the dbms, but you still need to do that somewhere.

Re: My Increasing Frustration with Clojure

#240

Earlier quoted context omitted.

You still need to do all the same things as before. Some things you move to the client, other things you move to the dbms. There isn't some functionality that magically disappears when you no longer have, for example, a PHP/Ruby/Python/JS/whatever server mediating between your client and your database.

The object-relational impedance mismatch disappears when the dbms is an immutable time series, which means a whole bunch of plumbing code does indeed evaporate

How do you decide who can write to and read from your data store?
Post reply on HN