6 ms·
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 eith
by brandonbloom 10y ago
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 one, hence the requirement that all arguments be actual sets. If you have sequences, you need to make an explicit decision to pay the cost of indexing (eg. via set or into functions) or you need custom code for your use case.
Sure, static or dynamic enforcement could help catch silly errors here, but then the author goes and poo poos on "greenfield" development of things like spec, despite the fact that would "fix the bug" exactly as requested by throwing when you gave non-sets to the set functions.
I've followed a lot of the discussion around the supposedly horrible way the Clojure community is run. So far, the absolutely only complaint that I can sympathize with is that communication could be faster, clearer, and softer. Alex Miller has made dramatic strides in improving this, but he's just one man. Cut these guys some slack, they work crazy hard to build and shepherd something awesome for free.
- jgalt212 10y ago> they work crazy hard to build and shepherd something awesome for free. I'm not so sure about that. I'd say that Clojure now exists and thrives to help Cognitect make money. This is no way a bad thing, only a reminder that there is no such thing as a free lunch. In a similar vein, Go exists to help make Google money. The original purpose of open sourcing it was different for Google (make the language more robust/better) than it was for Hickey (grow the language/community).
- brandonbloom 10y agoI anticipated this response to the word "free", but I stand by my statement. Clojure is _free_. If you don't want Cognitect stuff, don't use it. If you don't like how Rich/Cognitect et al are running the project, take your EPL licensed ball and go home. Similarly, in the case of Go: Substitute Rob/Google and BSD-ish license. Just because these languages serve the interests of their respective maintainers does not make them any less free to you. It may make the community less useful to _you_, but hey, they created these things to be useful to them. There's an implicitly mutually beneficial social contract around contributions and community. If you don't like that contract, don't use the language. In the very unlikely case that Cognitect or Google puts some company-specific stuff in the language in a way that actively destroys the good will of this social contract, then and only then do you have any right to complain.
- jgalt212 10y ago> does not make them any less free to you Of course not, but it does make them unencumbered. And I'm not complaining. I'm just saying that's cost (i.e. not free) of doing business with a sponsored open source language.
- brandonbloom 10y agoIf you take the stance of "nothing is free", then the word "free" isn't particularly useful.
- jgalt212 10y agoA+ extreme reductionism. I never said "nothing is free", nor implied that, but merely that users need to cognizant of the goals of "free" language maintainers (especially when there is a corporation rather than a person as BDFL) that do not necessarily align with the goals of the median or average user. Now that we are on this topic, I'm starting to think maybe it's worth paying for a programming language so that the goals of the maintainers are better aligned with the goals of the users. That being said, there is real value to the ability inspect the source. As such, it's very difficult to do open source as a paid product.
- calibraxis 10y agoThere is a history here. Please read: 1. https://web.archive.org/web/20100220100027/http://clojure.org/funding https://web.archive.org/web/20100220100027/http://clojure.or... 2. https://web.archive.org/web/20140704050611/http://clojure.org/funding https://web.archive.org/web/20140704050611/http://clojure.or... My own interpretation: programmer culture has such problems that someone actually considered corporate funding healthier than user donations.
- snaky 10y agoThere are many definitions of the term 'healthier'. But the links are pretty amusing. And now we have a first fork https://github.com/jaunt-lang/jaunt https://github.com/jaunt-lang/jaunt
- snaky 10y ago> The original purpose of open sourcing Go was different for Google (make the language more robust/better) I'm not so sure about that. I like the 'baseball cap' argument more. The quote is about React, but it may be relevant for Go as well > Facebook doesn't care if you use the Web, it only cares that you use Facebook. > So why release an open source Web framework at all? Because Facebook is battling Google for engineers. So you've got a big fight between two companies over which company is the coolest place to work, and both of them are companies that your grandparents love. How are you going to win this fight? One way is to have the hippest Web framework. > Basically, both Google and Facebook are desperate to find a baseball cap that they can put on backwards. Angular is Google's baseball cap. React is Facebook's. https://www.pandastrike.com/posts/20150311-react-bad-idea https://www.pandastrike.com/posts/20150311-react-bad-idea
- coldtea 10y ago>Clojure is a language for people who know what they are doing by people who know what they are doing. That can also be said for C, assembly and almost any language, even Brainfuck. And when there's not a speed/memory tradeoff for not having the language do the right thing (like e.g. is the case for some decisions in C), this just amounts to having the programmer do "busywork" -- manually do the work that the compiler/interpreter should have been doing instead. Blaming the programmer for such errors is thus a kind of "blaming the victim". The approach "The language X is totally fine, it's the programmer's problem who doesn't know what they're doing" for such cases, that is, cases where: 1) the right thing/warning could be inferred automatically 2) there's no (or not significant) speed/memory tradeoff to do so is a bad idea and those that propagate it should feel bad.
- brandonbloom 10y agoC absolutely is a language by/for people who know what they are doing. The fact that so many people are using it for so many things where modern safer languages now exist is not a failing of C or its designers... Regarding misusing the set functions: There is no busy work. Instead of (set/intersect some-set some-list) you just need to do (set/intersect some-set (set some-list)) to explicitly opt in to the speed tradeoff of performing set operations on lists. > is a bad idea and those that propagate it should feel bad. I don't feel bad about it at all. If Clojure hadn't followed the garbage-in/garbage-out strategy, it would have been too slow for production use. If they had added strong types early or Racket-style (read: slow) contracts, then we'd never have had the years of experience that led to the design of spec, which is new take on the problem space. In the case of the set functions, the right thing _can not_ be inferred automatically without a speed tradeoff.
- deleted 10y ago[deleted]
- dllthomas 10y ago> the author goes and poo poos [...] spec, despite the fact that would "fix the bug" exactly as requested by throwing when you gave non-sets to the set functions. I noticed that as well.
- thaumasiotes 10y ago> 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 one, hence the requirement that all arguments be actual sets. This made me very curious about efficient set union. Here's a pretty straightforward set union in python: def set_union(coll1, coll2): result = set() for item in coll1: result.add(item) for item in coll2: result.add(item) return result Apparently that isn't the efficient way to do it -- what is? Regardless, the article strongly suggests that one of the two arguments to clojure.set's union does offer fast set membership, since only the second argument is permitted to not be a set.
- brandonbloom 10y agocljs.user=> (source clojure.set/union) (defn union "Return a set that is the union of the input sets" ([] #{}) ([s1] s1) ([s1 s2] (if (< (count s1) (count s2)) (reduce conj s2 s1) (reduce conj s1 s2))) ([s1 s2 & sets] (let [bubbled-sets (bubble-max-key count (conj sets s2 s1))] (reduce into (first bubbled-sets) (rest bubbled-sets))))) nil cljs.user=> (source clojure.set/intersection) (defn intersection "Return a set that is the intersection of the input sets" ([s1] s1) ([s1 s2] (if (< (count s2) (count s1)) (recur s2 s1) (reduce (fn [result item] (if (contains? s2 item) result (disj result item))) s1 s1))) ([s1 s2 & sets] (let [bubbled-sets (bubble-max-key #(- (count %)) (conj sets s2 s1))] (reduce intersection (first bubbled-sets) (rest bubbled-sets))))) nil
- thaumasiotes 10y agoI 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 that type allows for it. My question was, why does efficient set union of two collections require one of the two collections to support fast membership tests? As an answer to that question, you've posted code that doesn't involve membership tests at all and supplied no discussion of why it is or isn't efficient.
- village-idiot 10y agoSo you're saying because I've run into these bugs in my own code, I clearly don't know what I'm doing and I should be using a language for someone of my intelligence?
- brandonbloom 10y agoNo, I'm saying you should stop and think about what you're doing.
- village-idiot 10y agoCool. So you're saying because I found bugs I'm not doing my job right? That I'm rushing and not thinking about what I'm doing?
- brandonbloom 10y agoYou're ignoring the fact that I don't believe clojure.set to be buggy.
- village-idiot 10y agoYou're not getting what I'm trying to communicate. Telling people that they're not doing a good job when you don't even know them only pisses people off, and eliminates any chance that they'll agree with you on principle. I was hoping highlighting that would make you realize that all you were saying to me was that I'm not doing a good job, but you didn't seem to get it. Each time I summarized what you said before, you changed your story to make it sound less bad. Ultimately I don't really care that much, this is the Internet and I don't have to interact with you after this. But I'd recommend not doing that to people IRL, they'll resent you.
- brandonbloom 10y ago> Telling people that they're not doing a good job when you don't even know them only pisses people off, and eliminates any chance that they'll agree with you on principle. Funny, that's exactly what the original poster did to the Clojure core team. > Each time I summarized You call it summarizing, I call it mischaracterizing. I stand by the position that if the original poster thinks that clojure.set is bugged: they don't know what they are talking about. That doesn't mean they suck at their job, that means they haven't actually stopped to think about the particularities of those functions.
- MikeOfAu 10y ago> Clojure is a language for people who know what they are doing by people who know what they are doing. Oh, goodie. I'm part of an elite club with high barriers to entry.
- spacemanmatt 10y agoExperience actually matters in software development. I'm not sure why you deride it as elitism.
- MikeOfAu 10y agoTone matters too.
- deleted 10y ago[deleted]
- ezy 10y agoAs 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...
- spicy_meatball 10y agoThis 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.