TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Idiomatic Errors in Clojure

97 点作者 harperlee5 个月前

10 条评论

jimbokun5 个月前
My take away:<p>Idiomatic Clojure error handling can be idiomatic Java error handling, idiomatic Erlang&#x2F;Elixir error handling, or idiomatic Haskell error handling.<p>If everything is idiomatic, is anything idiomatic?<p>(This article also makes me strangely appreciative of Go&#x27;s idiomatic error handling. Use multiple return values, so the error value is clearly visible in function signature and must at least be explicitly ignored by the caller. Avoids the action at a distance of exceptions, and the invisibility of errors in the dynamic approaches recommended in the article.)
评论 #42417636 未加载
评论 #42457392 未加载
评论 #42417976 未加载
phoe-krk5 个月前
Also note an implementation of Common Lisp condition system in Clojure that allows you to have CL-style condition handling: <a href="https:&#x2F;&#x2F;github.com&#x2F;IGJoshua&#x2F;farolero&#x2F;">https:&#x2F;&#x2F;github.com&#x2F;IGJoshua&#x2F;farolero&#x2F;</a>
thih95 个月前
A bit off topic, it took me a while to figure out that the article is about “handling errors in clojure in an idiomatic way” and not “error prone clojure code that gets written so often it can be considered idiomatic”. Especially since some of these can be controversial, e.g. error maps.
评论 #42417128 未加载
评论 #42416728 未加载
roenxi5 个月前
&gt; if something is expected then return either nil or some {:ok false :message &quot;...&quot;} value (and {:ok true :value ...} for success)<p>Maps used in this way are uncomfortable. You end up with a function (foo x y z) and in practice you don&#x27;t know how may values it is about to return. Technically one, but that one might be a map with who-knows-what in it.<p>There is a general API problem here of how to handle operations which really require multiple communication channels to report back with. I&#x27;m not sure if there is a good way to handle it, but complex objects as return value isn&#x27;t very satisfying. Although in practice I find it works great in exceptions because the map is secretly just a string that is about to be logged somewhere and discarded.
评论 #42414401 未加载
评论 #42415093 未加载
评论 #42415365 未加载
评论 #42416813 未加载
lbj5 个月前
A must-read for Clojurians.I especially appreciated that he took the time to comment on the correct use of assert, which is too often overlooked and makes debugging harder than it needs to be.
评论 #42416993 未加载
TacticalCoder5 个月前
They all feel kinda monadic&#x27;ish to me (and the term monad is used several times in TFA) and I kinda dig them when coupled with &quot;enhanced&quot; threading macros that shall short-circuit on an error but...<p>How&#x27;d that all work with Clojure <i>spec</i>? I use spec and spec on functions (<i>defn-spec</i>) all the time in Clojure. It&#x27;s my way to keep things sane in a dynamic language (and I know quite some swear by spec too).<p>I&#x27;d now need to spec, say, all my maps so that they&#x27;re basically a &quot;Maybe&quot; or &quot;Either&quot; with the right side being my actual specc&#x27;ed map and the left side being specc&#x27;ed as an error dealing thinggy?<p>Would that be cromulent? Did anyone try mixing such idiomatic error handling in Clojure mixed with specs and does it work fine?
评论 #42417097 未加载
eduction5 个月前
For failure maps, I’ve found it useful to have a :tried key, which is the parameter that in some sense “caused” the err, or a map of params if there are multiple.<p>I also usually have an error :type key.<p>I’ve also found it useful to distinguish between expected errs and those that should end execution more quickly. Clojure allows hierarchical keys with “derive” so I inherit these from a top level error key and set them as the :type. (Why not use exceptions - because I’ve already got exit flow and error reporting built around the maps.)
评论 #42416985 未加载
dustingetz5 个月前
- regarding the bulk of these patterns, which are all just different encodings of error values:<p>- the primary value prop of error values is they are concurrent, i.e. you can map over a collection with an effectful fn and end up with a collection of maybe errors (where error is encoded as nil, map, Either, whatever)<p>- exceptions cannot do this<p>- furthermore, clojure’s default collection operators (mapcat etc) are lazy, which means exceptions can teleport out of their natural call stack, which can be very confusing<p>- error values defend this<p>- the problem is that now you have a function coloring problem: most functions throw, but some functions return some error encoding<p>- this additional structure is difficult to balance, you’re now playing type tetris without a type system. Clojure works best when you can write short, simple code and fall into the pit of success. Type tetris is pretty much not allowed, it doesn’t scale, you’ll regret it<p>- you’ll also find yourself with a red function deep in your logic that is called by a blue function, at which point you’ll find your self doing the log-and-discard anti pattern<p>- therefore, i agree with the first bullet: it’s a hosted language, host exceptions are idiomatic, don’t over complicate it<p>- i do think error values can work great locally, for example (group-by (comp some ex-message) (map #(try-ok (f! %))), here i am using ex-message as a predicate. the point is you need to gather and rethrow asap to rejoin the language-native error semantics so your functions are no longer colored<p>- i am not an authority on this, just my experience having explored this a bit, wrote a big system once using a monadic error value encoding in clojure (using the funcool either type) and was very unhappy. The minute you see &gt;&gt;= in a clojure codebase, it’s over. (mlet is ok locally)<p>- one thing building Electric Clojure taught me, is that the language&#x2F;runtime can encode exception semantics “however” and still expose them to the user as try&#x2F;catch. Which means we can deliver the value prop of error values under the syntax of try&#x2F;catch.<p>- That means, interestingly, Electric v2’s exceptions are <i>concurrent</i> - which means an electric for loop can throw many exceptions at the same time, and if some of them resolve those branches can resume while the others stay parked.<p>- For Electric v3 we have not decided if we will implement try&#x2F;catch yet, because Electric userland code is essentially “pure” (given that IO is managed by the runtime and resource effects are managed by an effect system). Userland doesn’t throw, platform interop (database txns) is what throws, and we’ve found only very minor use cases for needing to catch that from Electric programs, again due to their purity. Having network failure not be your problem is really great for code complexity and abstraction!
评论 #42416569 未加载
layer85 个月前
&gt; It’s common to see (catch Throwable) sprinkled liberally across a Clojure codebase.<p>Just like (catch Exception), this also breaks the semantics of <i>InterruptedException</i>, which (to maintain its semantics) either has to be rethrown, or the catching code has to set the the current thread’s interrupt flag (<i>Thread::interrupt</i>).
whalesalad5 个月前
Great post this has cleared up a lot of things for me.
评论 #42416996 未加载