Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>Literal Octals</strong></p> <p>At one point I was reading in a matrix which used leading zeros to maintain proper rows and columns. Mathematically this is correct, since leading zero obviously don't alter the underlying value. Attempts to define a var with this matrix, however, would fail mysteriously with:</p> <pre><code>java.lang.NumberFormatException: Invalid number: 08 </code></pre> <p>which totally baffled me. The reason is that Clojure treats literal integer values with leading zeros as octals, and there is no number 08 in octal.</p> <p>I should also mention that Clojure supports traditional Java hexadecimal values via the <strong>0x</strong> prefix. You can also use any base between 2 and 36 by using the "base+r+value" notation, such as <strong>2r101010</strong> or <strong>36r16</strong> which are 42 base ten.</p> <hr> <p><strong>Trying to return literals in an <a href="http://clojure.org/reader#toc2" rel="noreferrer">anonymous function literal</a></strong></p> <p>This works:</p> <pre><code>user&gt; (defn foo [key val] {key val}) #'user/foo user&gt; (foo :a 1) {:a 1} </code></pre> <p>so I believed this would also work:</p> <pre><code>(#({%1 %2}) :a 1) </code></pre> <p>but it fails with:</p> <pre><code>java.lang.IllegalArgumentException: Wrong number of args passed to: PersistentArrayMap </code></pre> <p>because the <strong>#()</strong> reader macro gets expanded to</p> <pre><code>(fn [%1 %2] ({%1 %2})) </code></pre> <p>with the map literal wrapped in parenthesis. Since it's the first element, it's treated as a function (which a literal map actually is), but no required arguments (such as a key) are provided. In summary, the anonymous function literal does <strong>not</strong> expand to </p> <pre><code>(fn [%1 %2] {%1 %2}) ; notice the lack of parenthesis </code></pre> <p>and so you can't have any literal value ([], :a, 4, %) as the body of the anonymous function.</p> <p>Two solutions have been given in the comments. <strong>Brian Carper</strong> suggests using sequence implementation constructors (array-map, hash-set, vector) like so:</p> <pre><code>(#(array-map %1 %2) :a 1) </code></pre> <p>while <strong>Dan</strong> shows that you can use the <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/identity" rel="noreferrer">identity</a> function to unwrap the outer parenthesis:</p> <pre><code>(#(identity {%1 %2}) :a 1) </code></pre> <p>Brian's suggestion actually brings me to my next mistake...</p> <hr> <p><strong>Thinking that <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/hash-map" rel="noreferrer">hash-map</a> or <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/array-map" rel="noreferrer">array-map</a> determine the <em>unchanging</em> concrete map implementation</strong></p> <p>Consider the following:</p> <pre><code>user&gt; (class (hash-map)) clojure.lang.PersistentArrayMap user&gt; (class (hash-map :a 1)) clojure.lang.PersistentHashMap user&gt; (class (assoc (apply array-map (range 2000)) :a :1)) clojure.lang.PersistentHashMap </code></pre> <p>While you generally won't have to worry about the concrete implementation of a Clojure map, you should know that functions which grow a map - like <strong>assoc</strong> or <strong>conj</strong> - can take a <em>PersistentArrayMap</em> and return a <em>PersistentHashMap</em>, which performs faster for larger maps.</p> <hr> <p><strong>Using a function as the recursion point rather than a <a href="http://clojure.org/special_forms#toc11" rel="noreferrer">loop</a> to provide initial bindings</strong></p> <p>When I started out, I wrote a lot of functions like this:</p> <pre><code>; Project Euler #3 (defn p3 ([] (p3 775147 600851475143 3)) ([i n times] (if (and (divides? i n) (fast-prime? i times)) i (recur (dec i) n times)))) </code></pre> <p>When in fact <a href="http://clojure.org/special_forms#toc11" rel="noreferrer">loop</a> would have been more concise and idiomatic for this particular function:</p> <pre><code>; Elapsed time: 387 msecs (defn p3 [] {:post [(= % 6857)]} (loop [i 775147 n 600851475143 times 3] (if (and (divides? i n) (fast-prime? i times)) i (recur (dec i) n times)))) </code></pre> <p>Notice that I replaced the empty argument, "default constructor" function body <strong>(p3 775147 600851475143 3)</strong> with a loop + initial binding. The <strong>recur</strong> now rebinds the loop bindings (instead of the fn parameters) and jumps back to the recursion point (loop, instead of fn).</p> <hr> <p><strong>Referencing "phantom" vars</strong></p> <p>I'm speaking about the type of var you might define using the REPL - during your exploratory programming - then unknowingly reference in your source. Everything works fine until you reload the namespace (perhaps by closing your editor) and later discover a bunch of unbound symbols referenced throughout your code. This also happens frequently when you're refactoring, moving a var from one namespace to another.</p> <hr> <p><strong>Treating the for <a href="http://en.wikipedia.org/wiki/List_comprehension" rel="noreferrer">list comprehension</a> like an imperative for loop</strong></p> <p>Essentially you're creating a lazy list based on existing lists rather than simply performing a controlled loop. Clojure's <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/doseq" rel="noreferrer">doseq</a> is actually more analogous to imperative foreach looping constructs.</p> <p>One example of how they're different is the ability to filter which elements they iterate over using arbitrary predicates:</p> <pre><code>user&gt; (for [n '(1 2 3 4) :when (even? n)] n) (2 4) user&gt; (for [n '(4 3 2 1) :while (even? n)] n) (4) </code></pre> <p>Another way they're different is that they can operate on infinite lazy sequences:</p> <pre><code>user&gt; (take 5 (for [x (iterate inc 0) :when (&gt; (* x x) 3)] (* 2 x))) (4 6 8 10 12) </code></pre> <p>They also can handle more than one binding expression, iterating over the rightmost expression first and working its way left:</p> <pre><code>user&gt; (for [x '(1 2 3) y '(\a \b \c)] (str x y)) ("1a" "1b" "1c" "2a" "2b" "2c" "3a" "3b" "3c") </code></pre> <p>There's also no <strong>break</strong> or <strong>continue</strong> to exit prematurely.</p> <hr> <p><strong>Overuse of structs</strong></p> <p>I come from an OOPish background so when I started Clojure my brain was still thinking in terms of objects. I found myself modeling everything as a <strong>struct</strong> because its grouping of "members", however loose, made me feel comfortable. In reality, <strong>structs</strong> should mostly be considered an optimization; Clojure will share the keys and some lookup information to conserve memory. You can further optimize them by defining <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/accessor" rel="noreferrer">accessors</a> to speed up the key lookup process.</p> <p>Overall you don't gain anything from using a <strong>struct</strong> over a <strong>map</strong> except for performance, so the added complexity might not be worth it.</p> <hr> <p><strong>Using unsugared BigDecimal constructors</strong></p> <p>I needed a lot of <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html" rel="noreferrer">BigDecimals</a> and was writing ugly code like this:</p> <pre><code>(let [foo (BigDecimal. "1") bar (BigDecimal. "42.42") baz (BigDecimal. "24.24")] </code></pre> <p>when in fact Clojure supports BigDecimal literals by appending <strong>M</strong> to the number: </p> <pre><code>(= (BigDecimal. "42.42") 42.42M) ; true </code></pre> <p>Using the sugared version cuts out a lot of the bloat. In the comments, <strong>twils</strong> mentioned that you can also use the <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/bigdec" rel="noreferrer">bigdec</a> and <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/bigint" rel="noreferrer">bigint</a> functions to be more explicit, yet remain concise.</p> <hr> <p><strong>Using the Java package naming conversions for namespaces</strong></p> <p>This isn't actually a mistake per se, but rather something that goes against the idiomatic structure and naming of a typical Clojure project. My first substantial Clojure project had namespace declarations - and corresponding folder structures - like this:</p> <pre><code>(ns com.14clouds.myapp.repository) </code></pre> <p>which bloated up my fully-qualified function references:</p> <pre><code>(com.14clouds.myapp.repository/load-by-name "foo") </code></pre> <p>To complicate things even more, I used a standard <a href="http://maven.apache.org/" rel="noreferrer">Maven</a> directory structure:</p> <pre><code>|-- src/ | |-- main/ | | |-- java/ | | |-- clojure/ | | |-- resources/ | |-- test/ ... </code></pre> <p>which is more complex than the "standard" Clojure structure of:</p> <pre><code>|-- src/ |-- test/ |-- resources/ </code></pre> <p>which is the default of <a href="http://github.com/technomancy/leiningen" rel="noreferrer">Leiningen</a> projects and <a href="http://github.com/richhickey/clojure/" rel="noreferrer">Clojure</a> itself.</p> <hr> <p><strong>Maps utilize Java's equals() rather than Clojure's = for key matching</strong></p> <p>Originally reported by <strong>chouser</strong> on <a href="http://irc.freenode.net/#clojure" rel="noreferrer">IRC</a>, this usage of Java's <strong>equals()</strong> leads to some unintuitive results:</p> <pre><code>user&gt; (= (int 1) (long 1)) true user&gt; ({(int 1) :found} (int 1) :not-found) :found user&gt; ({(int 1) :found} (long 1) :not-found) :not-found </code></pre> <p>Since both <strong>Integer</strong> and <strong>Long</strong> instances of 1 are printed the same by default, it can be difficult to detect why your map isn't returning any values. This is especially true when you pass your key through a function which, perhaps unbeknownst to you, returns a long.</p> <p>It should be noted that using Java's <strong>equals()</strong> instead of Clojure's <strong>=</strong> is essential for maps to conform to the java.util.Map interface.</p> <hr> <p>I'm using <a href="http://pragprog.com/titles/shcloj/programming-clojure" rel="noreferrer">Programming Clojure</a> by Stuart Halloway, <a href="http://www.apress.com/book/view/1430272317" rel="noreferrer">Practical Clojure</a> by Luke VanderHart, and the help of countless Clojure hackers on <a href="http://irc.freenode.net/#clojure" rel="noreferrer">IRC</a> and the mailing list to help along my answers. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload