Fork me on GitHub
#clojure-dev
<
2022-07-28
>
dominicm13:07:49

Just to check, is (defprotocol p (f ^ISeq [_])) supposed to be supported? It exhibits the same error as CLJ-1180 on 1.11.1.

imre20:07:35

Just on the topic of protocols, in trying to make some things more performant, I just came across https://clojure.atlassian.net/browse/CLJ-1814`satisfies?` - is there any chance that would be looked at for a near release?

imre21:07:13

There aren’t any outstanding questions there as far as I see

seancorfield22:07:33

It says it is waiting on https://clojure.atlassian.net/browse/CLJ-2426 The following tickets are being considered for 1.12: https://clojure.atlassian.net/issues/?filter=10032 Neither of those satisfies? tickets are on that list.

seancorfield22:07:03

I think the push back has been "if you're using satisfies? you're already circumventing type-based dispatch so you're not on the performant path at that point"...?

imre09:07:49

Eh, huge facepalm on me for not noticing that it’s waiting on 2426…, thanks for the clarification

imre09:07:33

I know it isn’t selected for 1.12, that’s why I wrote “a near release”

imre09:07:09

That fast path thing is interesting. I saw satisfies? checks used to decide whether you can switch to a faster path but perhaps there’s a better way there

imre10:07:41

But if there is, I don’t know what it is. Tried the following just now, but looking at it now it was silly of me to even think it could work:

(ns user)

;; not under my control
(defprotocol FastPath
  (do-fast-path [this arg]))

;; under my control

(defprotocol SupportsFastPath
  (supports-fast-path? [this]))

(extend-protocol SupportsFastPath
  nil (supports-fast-path? [_] false)
  Object (supports-fast-path? [_] false)
  
  ;; need to put a type here so using the interface
  ;; that the protocol generates
  user.FastPath (supports-fast-path? [_] true))

(extend-protocol FastPath
  ;; but this obviously won't make
  ;; implementers of IPersistentMap also implement user.FastPath...
  clojure.lang.IPersistentMap
  (do-fast-path [_ arg] arg))

(comment

  (supports-fast-path? nil)
  ;; false

  (supports-fast-path? 1)
  ;; false

  (do-fast-path {} :fast)
  ;; :fast

  (supports-fast-path? {})
  ;; false unfortunately

  (satisfies? FastPath {})
  ;; true but slow

  )

imre10:07:33

So some logic could go onto the fast path but it needs to check whether the data is has supports the fast path. Checking with satisfies? is slow. Is there another way I’m missing perhaps?

dominicm10:07:47

I've not read closely, but I believe one pattern for this kind of thing is to have an implementation of your protocol for Object, and then when you land into that implementation call extend-protocol

imre13:07:28

I’m not sure how that would work. Here’s my case a bit shortened:

(defn supports-fast-path? [x]
  (satisfies? ThirdPartyProtocol x))

(if (supports-fast-path? input)
  (fast-path input args)
  (slow-path input args))
This is library code. The only thing I can assume is that if input implements ThirdPartyProtocol then I can go down the fast path. I have no control over what input is or how it implements ThirdPartyProtocol which I also don’t have any control over.

dominicm13:07:32

You extend SupportsFastPath to Object, and if the object you have satisfies ThirdPartyProtocol you extend it's class to SupportsFastPath.

dominicm13:07:47

Then you only call satisfies? once per class

imre13:07:31

so build up my own “method impl cache”-like thing

imre13:07:26

Thanks for the explanation. I suppose that’s doable albeit rather work-aroundy

imre13:07:05

The point I was trying to make with the example is that satisfies? should not be dismissed as “you’re already on the slow path if you call it”

dominicm13:07:54

This pattern is straight from Alex's book iirc

imre14:07:22

programming clojure you mean?

imre14:07:27

and if yes, do you know where in it? I just opened my copy but couldn’t find it

dominicm14:07:57

I'm not sure, Alex has talked about it here a few times.

imre14:07:47

Thanks for the info anyway, this made me curious. I’ll search around a bit

imre14:07:28

Because I still feel this should not need a workaround