5 ms·
Clojure Style Guide
- danneu 12y ago;; good (defn print-seq [s] (when (seq s) (prn (first s)) (recur (rest s)))) ;; bad (defn print-seq [s] (when-not (empty? s) (prn (first s)) (recur (rest s)))) Why use `seq` instead of `not-empty`? (defn print-seq [s] (when (not-empty s) (prn (first s)) (recur (rest s))))
- deleted 12y ago[deleted]
- mullr 12y ago(when (seq s) ...) reads to me as "do this as long as I can treat s sequentially". The following operations on s require it to be seqable, so it's like a runtime type check. not-empty is less direct, and feels like it's assuming that s is seqable. Of course, not-empty is implemented with (when (seq)), so there's no REAL difference. At the end of the day, (when (seq)) is what people use.
- mkremins 12y agoThis interpretation is error-prone. (seq 1), for instance, throws an IllegalArgumentException at runtime. Meanwhile, (seq nil) returns a falsey value even though in many cases it's possible to transparently pass nil in place of a collection of any kind. Essentially, seq already assumes that its argument is seqable. Don't use it to test an argument of unknown type for seqability; prefer something like the seqable? function from core.incubator [1], or a different core function like coll? or sequential? where the semantics of one of these will do. [1] https://github.com/clojure/core.incubator/blob/master/src/main/clojure/clojure/core/incubator.clj#L83 https://github.com/clojure/core.incubator/blob/master/src/ma...
- justwannareply 12y agoI don't know any Clojure, but I guess it's for the same reason why if lst: # do something with lst is preferred to if len(lst) > 0: # do something with lst in Python. It becomes more obvious when you use descriptive names: if customers: # do something with customers
- tel 12y ago... but involves such an overloading of the nature of truthiness! All to match a really ad hoc syntax sugaring of English? if X ==> if there exists some X
- kyllo 12y agoIn Python, "if there exists some X" would be more like if x is not None: In Python, [] (empty list) and {} (empty dict) are == False but are not None. They exist, and their types are List and Dict rather than NoneType, but they are "falsey" because they are empty.
- diego 12y ago(not-empty coll) is the same as (when (seq coll) coll)
- thom 12y agoYeah, it's worth noting that not-empty is the flip-side to empty (which returns an empty coll of the same type as its argument), as opposed to empty?.
- bozhidar 12y agoThere's still debate on this (https://github.com/bbatsov/clojure-style-guide/issues/44 https://github.com/bbatsov/clojure-style-guide/issues/44). It's the suggested style mostly because Rich (Clojure's creator) promotes it.
- thom 12y agoThe thing I most scratch my head about in my Clojure code is when to optimise function arguments for each of thread-first/thread-last/partial etc. Some patterns are fairly established, like predicate first, coll last, but I'd be intrigued to hear some more rules of thumb.
- csdrane 12y agoSeems to me like Clojure is experience a popularity surge on HN lately. I wonder what's driving this. Maybe my perception is just biased because I'm currently learning Clojure.
- mateuszf 12y agoThat's strange, because I also noticed that, and I'm also starting to learn Clojure.
- fariasvp 12y agoSame here
- eruditely 12y agoI have also been convinced to start learning clojure. Also on the hn posting thread, a company called fracture had a relatively interesting job application, and if the kind of people who write clojure write tongue in cheek shit like then I want to start learning.
- roryokane 12y agoClojure stories are experiencing a slight surge, but not an unusual one. When I search on Hacker News by date, like https://hn.algolia.com/?q=clojure#!/story/forever/prefix/0/clojure%20date%3E1404878400 https://hn.algolia.com/?q=clojure#!/story/forever/prefix/0/c... (UNIX timestamps format), I can calculate that there are more stories with “Clojure” in the title than last month, but it is within normal fluctuations. In the last four month-long periods, beginning with April 9 to May 9 and ending with July 9 to August 9, the number of “Clojure” stories were [36, 41, 32, 41]. So the 41 stories of the most recent month is more than the previous month, but the same as the month before that.
- modarts 12y agoMy completely unfounded theory: Clojurescript is starting to get a lot of traction because of David Nolen's Om which has caused a surge of interest based on its excellent performance characteristics and clean and easy to reason about code (mainly due to the use of persistent data structures). This naturally leads to people getting interested in Clojure the language as well
- film42 12y agoI'm a bit confused about the require refer all vs use. Can someone explain why use is bad in that context (or in general)? Link: https://github.com/bbatsov/clojure-style-guide#prefer-require-over-use https://github.com/bbatsov/clojure-style-guide#prefer-requir... UPDATE: Looks like there's a GH issue thread on the subject: https://github.com/bbatsov/clojure-style-guide/issues/16 https://github.com/bbatsov/clojure-style-guide/issues/16
- mkremins 12y agoBoth :use and :require :refer :all slurp symbols into your namespace unqualified. This behavior can cause confusion when someone reading your code tries to figure out which symbols are defined where. Most of the time, more explicit alternatives are preferred: (:require [foo :as f]) gives the required namespace a short alias with which symbols defined in that namespace can be qualified, while (:require [foo :refer [bar baz quux]]) explicitly provides a set of symbols to import unqualified. Generally speaking, :require :refer :all is also considered non-idiomatic. In fact, ClojureScript has explicitly avoided supporting both :require :refer :all and naked :use [1]. Backwards compatibility seems to be the only reason either is still supported by Clojure on the JVM. [1] https://groups.google.com/forum/#!msg/clojurescript/SzYK08Oduxo/BfFiia0wOO4J https://groups.google.com/forum/#!msg/clojurescript/SzYK08Od...
- film42 12y agoI totally agree about requiring :as or :refer to specific functions, but it still seems like the clojure team prefers naked `use` over `require refer all`, so should the style guide be changed to allow naked `use` in some circumstances? I guess a popular example is `(:use clojure.test)`
- mkremins 12y agoMakes sense to me, although I suppose there's probably an argument to be made in favor of the uniformity that comes with using :require for everything. (:use clojure.test) is probably a worthy exception – 90% of the time I see :use in the wild, it's in exactly that context :)
- dj-wonk 12y agoI agree that this is a pretty good style guide, in the sense that it captures a large portion of what Clojure programmers consider to be good style. A few words about semicolons for comments. Lots of Clojure code uses ; and ;; and ;;; to indicate levels of comment nesting. I get that multiple semicolons are intended to indicate hierarchy / sections / nesting. Some editors use it for auto-indentation. (However, I don't think editors really need multiple semicolons to do a good job of indentation; mine does fine without.) Personally, I find one semicolon to be enough to indicate a comment at any level. Context tells the rest. So I am not on-board with multiple semicolons. One, it looks ugly to me. Two, using more than one seems unnecessary -- and unnecessary things are good to avoid unless they add value. Who else agrees? Is there something I'm missing?
- th0ma5 12y agoSometimes I use an editor with a highlight and comment feature, and if I comment out a block of code, some of those intertwined comments will have the double semicolon. Another neurosis I have is using multiple for stuff that I've yet to delete but want to make sure I don't accidentally uncomment but that is dumb and what version control solves. Outside of these unconvincing uses I'm not familiar with this nested comment idea but I couldn't criticize it given the funny things I do.
- TheMiller 12y agoI believe that this convention is borrowed from Common Lisp. I always thought of it more as a way to highlight importance. Three semicolons for block comments outside of top-level constructs, which usually explain the purpose or usage of the following expression (usually a function definition). Two for comments inline with function body code. And one for trailing comments on a line, where space is limited and the comment is least important to understand code structure. The conventions are even mentioned in the Common Lisp specifications: http://www.lispworks.com/documentation/HyperSpec/Body/02_ddb.htm http://www.lispworks.com/documentation/HyperSpec/Body/02_ddb...
- lispm 12y agoThe use of one or more semicolons is older than Common Lisp. Maclisp had it in the 1970s, but earlier with different semantics - it had semantics for formatting code. Then it was changed a bit with the use of Emacs.
- dandrews 12y agoMuch as I loathe self-proclaimed "best practice", I find this style guide agreeable. I'll quibble with the author's superfluous use of comp/partial as a documentation aid, and the picayune advice to use single-sentence-spacing in comments deserves an eyeroll. But for the most part this is all good stuff, and is worthy of consideration. Pay attention, n00bs.
- islon 12y ago`Prefer .. to -> when chaining method calls in Java interop.` That works if there's only Java calls in your chain. I, for one, prefer to use the more generic threading macros.