Fork me on GitHub
#clojurescript
<
2022-12-16
>
valerauko12:12:00

i'm having problems with protocols in clojurescript

valerauko12:12:29

for some reason it doesn't seem to pass keywords as first argument

valerauko12:12:00

if i have a protocol fn (expand [_ _]) and try to call it like (expand :some-keyword {:a 1}) i get the same map in both arguments

valerauko12:12:04

if i have a protocol fn (href [_] [_ _] [_ _ _]) then trying to call it as (href ::some-keyword) will error saying there's no implementation for the protocol for null

valerauko12:12:23

the protocols are defined in cljc files

Ferdinand Beyer12:12:54

Can you share more code? It seems like you are not passing the type that implements the protocol as first argument

Ferdinand Beyer12:12:18

E.g. do you use defprotocol and extend-protocol? Or extend-type or reify?

valerauko12:12:34

i'm passing a hardcoded keyword

valerauko12:12:38

that's why i'm super confused

valerauko12:12:57

it says i'm passing nil or an arraymap when i'm clearly not

valerauko12:12:05

i use defprotocol and extend-protocol

Ferdinand Beyer12:12:24

Can you share how you use defprotocol and extend-protocol?

thheller12:12:36

did you implement the protocol for keywords?

thheller12:12:23

the first arg is always the thing that implements the protocol. so if you don't implement it for keywords you get an error

valerauko12:12:51

in that case i get a protocol not implemented for type error, not this

thheller12:12:31

what is "this" precisely?

valerauko12:12:53

Uncaught Error: No protocol method ByName.href defined for type null: 
when the callsite is hard coded to this:
(href ::web/ping)

valerauko12:12:06

i have no idea how it manages to turn a hardcoded keyword into null

thheller12:12:44

it very likely doesn't. did you verify that you are looking at your exact piece of code? ie. by commenting it out?

thheller12:12:12

and you implemented the prtocol in a non-recursive fashion where it calls itself, which maybe some other logic you did?

valerauko12:12:21

Hmm that narrowed it down a little. So I have this protocol

(defprotocol ByName
  (href [_] [_ _] [_ _ _]))
Implemented for Keyword like this
(extend-protocol routes/ByName
  Keyword
  (href
   ([route]
    (js/alert "a" route)
    (href route nil nil))
   ([route params]
    (js/alert "b" route)
    (href route params nil))
   ([route params query]
    (js/alert "c" route)
    (easy/href route params query))))
I get alert "a" out of this but never alert "b". The super annoying thing about this is that this exact code (without the alerts of course) works without problem in another project (where the protocol is defined in a cljs file and not a cljc)

valerauko12:12:53

Similarly I have a protocol

(defprotocol Expand
  (expand [_ _]))
Implemented like this
(extend-protocol routes/Expand
  Keyword
  (expand
   [route-name opts]
   (expand {:name route-name} opts))

  PersistentArrayMap
  (expand
   [{route-name :name :as route} _]
   (conj route (route-defs route-name)))

  PersistentHashMap
  (expand
   [{route-name :name :as route} _]
   (conj route (route-defs route-name))))
And even if I call this like (expand :foo {}) it matches on the PersistentArrayMap just throwing the keyword away (the Keyword implementation never gets called -- confirmed with console.logs)

valerauko12:12:08

I have never seen cljs behave like this and I got no idea what I could've messed up. I've tried clearing the .shadow-cljs and public/js folders, no luck.

valerauko13:12:04

Not even sudo rm -rf node_modules .shadow-cljs public/js helped...

thheller13:12:20

I'd suggest not making a muti arity protocol in the first place

thheller13:12:33

make a regular defn for that, which then calls the protocol

valerauko13:12:00

i can't because of circular dependencies

thheller13:12:23

for a defn?

thheller13:12:44

anything that call the protocol can call a defn

valerauko13:12:08

i understand that. i just realized that in this case href doesn't have to be a protocol. that however doesn't explain the issue with the protocol that has a sinlgle [ ] arity

thheller13:12:10

the code likely is just buggy. I see at least one above

thheller13:12:27

expand in for keyword calling expand?

thheller13:12:48

but the protocol is in another namespace, so why is this not qualified? or do you have a refer?

valerauko13:12:18

(not refering and instead using routes/expand does not fix the issue)