Fork me on GitHub
#clojure
<
2022-02-20
>
Burin09:02:34

Hi there,

(defn fn-demo 
  [a b & args]
  [:a a :b b :args args])

(fn-demo "aa" "bb" "cc" "dd")
;;=> [:a "aa" :b "bb" :args ("cc" "dd")]

However 

(apply fn-demo "aa" "bb" "cc" "dd")

Return

[:a "aa" :b "bb" :args ("cc" \d \d)]

why is the result of the apply function not returning

[:a "aa" :b "bb" :args ("cc" "dd")]

p-himik09:02:14

Because apply expects a collection of arguments as its last argument.

p-himik09:02:29

And "dd" is a collection of characters.

p-himik09:02:09

So from the perspective of apply, "dd" in the last position is exactly the same as [\d \d].

gratitude-thank-you 2
borkdude11:02:03

Aside from the source code, where can I learn more about how protocols in Clojure are implemented under the hood? E.g. talks or articles.

ghadi11:02:24

I gave a talk at the last jvmls that goes into some detail

gratitude 1
borkdude11:02:26

I actually saw that talk, but I bet I forgot most of it already

borkdude12:02:21

This actually answers one of my questions. If you want better performance for e.g. doing nothing on a String but just returning the String, it will look up the protocol impl via a map. But if you construct a type which holds that string, e.g. ConstantFoo and implement the protocol on that type, it will go right through the interface which can be faster (on hot paths, like in my case, an interpreter)

borkdude17:02:43

Good talk btw

1
1
mkvlr17:02:49

this this a bug?

clj                                                                                                                                                                                                  ✘ 130 
Clojure 1.10.3
user=> (require 'clojure.datafy)
nil
user=> (contains? (:publics (clojure.datafy/datafy (find-ns 'clojure.core))) :foo)
Execution error (ClassCastException) at user/eval3 (REPL:1).
class clojure.lang.Symbol cannot be cast to class clojure.lang.Keyword (clojure.lang.Symbol and clojure.lang.Keyword are in unnamed module of loader 'app')

1
mkvlr17:02:06

user=> *e
#error {
 :cause "class clojure.lang.Symbol cannot be cast to class clojure.lang.Keyword (clojure.lang.Symbol and clojure.lang.Keyword are in unnamed module of loader 'app')"
 :via
 [{:type java.lang.ClassCastException
   :message "class clojure.lang.Symbol cannot be cast to class clojure.lang.Keyword (clojure.lang.Symbol and clojure.lang.Keyword are in unnamed module of loader 'app')"
   :at [clojure.lang.Keyword compareTo "Keyword.java" 114]}]
 :trace
 [[clojure.lang.Keyword compareTo "Keyword.java" 114]
  [clojure.lang.Util compare "Util.java" 153]
  [clojure.lang.RT$DefaultComparator compare "RT.java" 283]
  [clojure.lang.PersistentTreeMap doCompare "PersistentTreeMap.java" 330]
  [clojure.lang.PersistentTreeMap entryAt "PersistentTreeMap.java" 317]
  [clojure.lang.PersistentTreeMap containsKey "PersistentTreeMap.java" 97]
  [clojure.lang.RT contains "RT.java" 834]
  [clojure.core$contains_QMARK_ invokeStatic "core.clj" 1494]
  [clojure.core$contains_QMARK_ invoke "core.clj" 1486]
  [user$eval3 invokeStatic "NO_SOURCE_FILE" 1]
  [user$eval3 invoke "NO_SOURCE_FILE" 1]
  [clojure.lang.Compiler eval "Compiler.java" 7181]
  [clojure.lang.Compiler eval "Compiler.java" 7136]
  [clojure.core$eval invokeStatic "core.clj" 3202]
  [clojure.core$eval invoke "core.clj" 3198]
  [clojure.main$repl$read_eval_print__9110$fn__9113 invoke "main.clj" 437]
  [clojure.main$repl$read_eval_print__9110 invoke "main.clj" 437]
  [clojure.main$repl$fn__9119 invoke "main.clj" 458]
  [clojure.main$repl invokeStatic "main.clj" 458]
  [clojure.main$repl_opt invokeStatic "main.clj" 522]
  [clojure.main$main invokeStatic "main.clj" 667]
  [clojure.main$main doInvoke "main.clj" 616]
  [clojure.lang.RestFn invoke "RestFn.java" 397]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.RestFn applyTo "RestFn.java" 132]
  [clojure.lang.Var applyTo "Var.java" 705]
  [clojure.main main "main.java" 40]]}

mkvlr17:02:18

(contains? (into (sorted-map) {'foo 'bar}) :foo) is a more minimal repro. So contains? throws for heterogenous types that cannot be compared. TIL

p-himik17:02:32

Not a bug indeed - datafy here returns a sorted map, and you can't use them with keys that you can't compare between each other. Even in such operations as contains? and dissoc. Here's a recent discussion with some links: https://clojurians.slack.com/archives/C03S1KBA2/p1643745537586049