Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Clojure: The Bad Parts

Clojure: The Bad Parts

Slide deck from my talk at Partial Conf 2017.

Avatar for Bozhidar Batsov

Bozhidar Batsov

May 20, 2025
Tweet

More Decks by Bozhidar Batsov

Other Decks in Programming

Transcript

  1. Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: i-dont-exist

    in this context, compiling:(one_man_wiki/views.clj:18) at clojure.lang.Compiler.analyze(Compiler.java:6281) at clojure.lang.Compiler.analyze(Compiler.java:6223) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5618) at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5054) at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3674) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6453) at clojure.lang.Compiler.analyze(Compiler.java:6262) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6443) at clojure.lang.Compiler.analyze(Compiler.java:6262) at clojure.lang.Compiler.access$100(Compiler.java:37) at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:518) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6455) at clojure.lang.Compiler.analyze(Compiler.java:6262) at clojure.lang.Compiler.analyze(Compiler.java:6223) at clojure.lang.Compiler.eval(Compiler.java:6515) at clojure.lang.Compiler.load(Compiler.java:6952) at clojure.lang.RT.loadResourceScript(RT.java:359) at clojure.lang.RT.loadResourceScript(RT.java:350) at clojure.lang.RT.load(RT.java:429) at clojure.lang.RT.load(RT.java:400) at clojure.core$load$fn__4890.invoke(core.clj:5415) at clojure.core$load.doInvoke(core.clj:5414) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:5227) at clojure.core$load_lib.doInvoke(core.clj:5264) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:603) at clojure.core$load_libs.doInvoke(core.clj:5298) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:603) at clojure.core$require.doInvoke(core.clj:5381) at clojure.lang.RestFn.invoke(RestFn.java:457) at one_man_wiki.handler$eval1564$loading__4784__auto____1565.invoke(handler.clj:1) at one_man_wiki.handler$eval1564.invoke(handler.clj:1) at clojure.lang.Compiler.eval(Compiler.java:6511) at clojure.lang.Compiler.eval(Compiler.java:6501) at clojure.lang.Compiler.load(Compiler.java:6952) at clojure.lang.RT.loadResourceScript(RT.java:359) at clojure.lang.RT.loadResourceScript(RT.java:350) at clojure.lang.RT.load(RT.java:429) at clojure.lang.RT.load(RT.java:400) at clojure.core$load$fn__4890.invoke(core.clj:5415) at clojure.core$load.doInvoke(core.clj:5414) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:5227) at clojure.core$load_lib.doInvoke(core.clj:5264) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:603) at clojure.core$load_libs.doInvoke(core.clj:5298) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:603) at clojure.core$require.doInvoke(core.clj:5381) at clojure.lang.RestFn.invoke(RestFn.java:421) at user$eval1.invoke(NO_SOURCE_FILE:1) at clojure.lang.Compiler.eval(Compiler.java:6511) at clojure.lang.Compiler.eval(Compiler.java:6500) at clojure.lang.Compiler.eval(Compiler.java:6477) at clojure.core$eval.invoke(core.clj:2797) at clojure.main$eval_opt.invoke(main.clj:297) at clojure.main$initialize.invoke(main.clj:316) at clojure.main$null_opt.invoke(main.clj:349) at clojure.main$main.doInvoke(main.clj:427) at clojure.lang.RestFn.invoke(RestFn.java:421) at clojure.lang.Var.invoke(Var.java:419) at clojure.lang.AFn.applyToHelper(AFn.java:163) at clojure.lang.Var.applyTo(Var.java:532) at clojure.main.main(main.java:37) Caused by: java.lang.RuntimeException: Unable to resolve symbol: i-dont-exist in this context at clojure.lang.Util.runtimeException(Util.java:170) at clojure.lang.Compiler.resolveIn(Compiler.java:6766) at clojure.lang.Compiler.resolve(Compiler.java:6710) at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6671) at clojure.lang.Compiler.analyze(Compiler.java:6244) ... 66 more
  2. No.

  3. (defn str "With no args, returns the empty string. With

    one arg x, returns x.toString(). (str nil) returns the empty string. With more than one arg, returns the concatenation of the str values of the args." {:tag String :added "1.0" :static true} (^String [] "") (^String [^Object x] (if (nil? x) "" (. x (toString)))) (^String [x & ys] ((fn [^StringBuilder sb more] (if more (recur (. sb (append (str (first more)))) (next more)) (str sb))) (new StringBuilder (str x)) ys)))
  4. (defn str "With no args, returns the empty string. With

    one arg x, returns x.toString(). (str nil) returns the empty string. With more than one arg, returns the concatenation of the str values of the args." {:tag String :added "1.0" :static true}
  5. (defun cider-interactive-eval (form &optional callback bounds additional-params) "Evaluate FORM and

    dispatch the response to CALLBACK. If the code to be evaluated comes from a buffer, it is preferred to use a nil FORM, and specify the code via the BOUNDS argument instead. This function is the main entry point in CIDER's interactive evaluation API. Most other interactive eval functions should rely on this function. If CALLBACK is nil use `cider-interactive-eval-handler'. BOUNDS, if non-nil, is a list of two numbers marking the start and end positions of FORM in its buffer. ADDITIONAL-PARAMS is a plist to be appended to the request message. If `cider-interactive-eval-override' is a function, call it with the same arguments and only proceed with evaluation if it returns nil."
  6. (defn str "Converts something to a string. With no args,

    returns the empty string. With one arg X, returns `x.toString()`. `(str nil)` returns the empty string. With more than one arg, returns the concatenation of the string values of the args." {:tag String :added "1.0" :static true}
  7. (ns ^{:author "Stuart Sierra, Stuart Halloway, David Liebke"} "Clojure String

    utilities It is poor form to (:use clojure.string). Instead, use require with :as to specify a prefix, e.g. (ns your.namespace.here (:require [clojure.string :as str])) Design notes for clojure.string: 1. Strings are objects (as opposed to sequences). As such, the string being manipulated is the first argument to a function; passing nil will result in a NullPointerException unless documented otherwise. If you want sequence-y behavior instead, use a sequence. 2. Functions are generally not lazy, and call straight to host methods where those are available and efficient. 3. Functions take advantage of String implementation details to write high-performing loop/recurs instead of using higher-order functions. (This is not idiomatic in general-purpose application code.) 4. When a function is documented to accept a string argument, it will take any implementation of the correct *interface* on the host platform. In Java, this is CharSequence, which is more general than String. In ordinary usage you will almost always pass concrete strings. If you are doing something unusual, e.g. passing a mutable implementation of CharSequence, then thread-safety is your responsibility." clojure.string (:refer-clojure :exclude (replace reverse)) (:import (java.util.regex Pattern Matcher) clojure.lang.LazilyPersistentVector))
  8. (defonce ^:dynamic ^{:private true :doc "A ref to a sorted

    set of symbols representing loaded libs"} *loaded-libs* (ref (sorted-set)))
  9. (defn agent-errors "DEPRECATED: Use 'agent-error' instead. Returns a sequence of

    the exceptions thrown during asynchronous actions of the agent." {:added "1.0" :deprecated "1.2"} [a] (when-let [e (agent-error a)] (list e))) (defn clear-agent-errors "DEPRECATED: Use 'restart-agent' instead. Clears any exceptions thrown during asynchronous actions of the agent, allowing subsequent actions to occur." {:added "1.0" :deprecated "1.2"} [^clojure.lang.Agent a] (restart-agent a (.deref a)))
  10. How do you indicate how some macro is supposed to

    be indented by Clojure editors?
  11. Common Metadata • version added (e.g. “:added”) • version compatibility

    broken (e.g. “:changed”) • version when deprecated (e.g. “:deprecated”) • superseded by • related symbols (e.g. “:see also”) • indentation speci fi cation
  12. •don’t require CA for doc improvements •accept doc improvements via

    GitHub •have a simpli fi ed review process for doc improvements