Support for named implementations of multimethods

22 views
Skip to first unread message

Dennis Schridde

unread,
Jun 7, 2022, 6:31:22 AMJun 7
to cur...@googlegroups.com
Hello!

https://clojuredocs.org/clojure.core/
defmethod#example-542692c7c026201cdc3269cd and https://clojuredocs.org/
clojure.core/defmethod#example-5db314cbe4b0ca44402ef7d4 suggest that a
definition like the following is allowed:

```
(defmulti my-multi (fn [,,,] ,,,))
(defmethod my-multi String my-string-multi [,,,] ,,,)
```

i.e. between the dispatch value (here: "String") and the argument list (here:
"[,,,]") it is allowed to fit in a name for this implementation of the
multimethod. I can confirm that this works and that the name shows up in
stacktraces as https://clojuredocs.org/uc/gstamp suggested.

Sadly this trips Cursive. It complains that "my-string-multi cannot be
resolved" and then does not detect the argument list, so that it will also
complain when the arguments are referenced from the function body.

Best regards,
Dennis


Tamas (onetom) Herman

unread,
Jun 15, 2022, 12:34:41 AMJun 15
to Cursive
What's the purpose of specifying a custom name?
Is it just about stacktrace readability, or are there any other benefits too?
I do use such facility in high-order functions, like middlewares, for the exact same reason.

Maybe we should provide some examples, which would highlight this benefit:

(defn mk-nudger [x]
    (fn nudger [delta] (+ x delta) (throw (ex-info "Bamm!" {}))))
(def nudge123 (mk-nudger 123))
=> #'user/nudge123
(nudge123 7)
Execution error (ExceptionInfo) at user/mk-nudger$nudger (user.clj:2).
Bamm!
clojure.lang.ExceptionInfo: Bamm! {}
    at user$mk_nudger$nudger__24196.invoke(user.clj:2)
    at user$eval24211.invokeStatic(user.clj:69)
    at user$eval24211.invoke(user.clj:69)

and without the `nudger` name:

(defn mk-nudger [x]
    (fn [delta] (+ x delta) (throw (ex-info "Bamm!" {}))))
(def nudge123 (mk-nudger 123))
(nudge123 7)
Execution error (ExceptionInfo) at user/mk-nudger$fn (user.clj:2).
Bamm!
clojure.lang.ExceptionInfo: Bamm! {}
    at user$mk_nudger$fn__24217.invoke(user.clj:2)
    at user$eval24224.invokeStatic(user.clj:69)
    at user$eval24224.invoke(user.clj:69)

-- 
  tom

Dennis Schridde

unread,
Jun 15, 2022, 7:42:06 AMJun 15
to Cursive, Tamas (onetom) Herman
On Mittwoch, 15. Juni 2022 06:34:41 CEST Tamas (onetom) Herman wrote:
> What's the purpose of specifying a custom name?
> Is it just about stacktrace readability, or are there any other benefits
> too?

Easier-to-read stacktraces are the only benefit I know of.

> I do use such facility in high-order functions, like middlewares, for the
> exact same reason.

I use it when converting my structured log data into the format required by my
logging library (OpenTelemetry SDK):

(defmulti put-attribute-kv (fn [_ _ v]
(if-let [t (and (instance? List v)
(all-of-same-type v))]
[t]
(class v))))

(defmethod put-attribute-kv Keyword keyword-attribute [b k v]
(.put ^AttributesBuilder b (AttributeKey/stringKey (name k)) (name v)))

(defmethod put-attribute-kv String string-attribute [b k v]
(.put ^AttributesBuilder b (AttributeKey/stringKey (name k)) v))

,,,

(defn map->Attributes ^Attributes [m]
(.build
^AttributesBuilder (reduce-kv put-attribute-kv
(Attributes/builder)
m)))

In my case I could also determine which implementation the exception comes
from by looking at line numbers, but having the name in the stacktrace makes
it quite a bit more convenient.

--Dennis


Imre Kószó

unread,
Jun 15, 2022, 9:20:19 AMJun 15
to Cursive

Imre Kószó

unread,
Jun 15, 2022, 9:22:30 AMJun 15
to Cursive
What's the purpose of specifying a custom name?

From the GH issue it appears it also helps with multi-arity implementations https://github.com/cursive-ide/cursive/issues/899#issuecomment-639085186 
Reply all
Reply to author
Forward
0 new messages