This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-01-30
Channels
- # announcements (5)
- # babashka (2)
- # beginners (85)
- # cider (59)
- # cljs-dev (2)
- # clojure (10)
- # clojure-europe (61)
- # clojure-gamedev (20)
- # clojure-nl (2)
- # clojure-norway (9)
- # clojure-uk (5)
- # cursive (24)
- # data-science (4)
- # datascript (8)
- # emacs (1)
- # fulcro (8)
- # graalvm (30)
- # gratitude (9)
- # hyperfiddle (71)
- # introduce-yourself (1)
- # jackdaw (1)
- # leiningen (8)
- # london-clojurians (1)
- # missionary (3)
- # other-languages (10)
- # pathom (8)
- # pedestal (18)
- # polylith (4)
- # proletarian (5)
- # reitit (7)
- # releases (4)
- # ring (8)
- # sci (10)
- # shadow-cljs (27)
- # squint (3)
- # tools-deps (2)
- # xtdb (17)
I feel like there's been some recent discussion about it but couldn't find it.
Just to confirm - there are no ways, existing or planned, to easily decorate a protocol method on its implementation, right? Apart from using things like https://github.com/deckchair-technicians/bowen.
So e.g. if type T
implements methods a
, b
, c
on protocol P
and I want to wrap only the implementation of a
with my own code, I currently have to specify all those methods in reify
or my own type that delegates b
and c
to the wrapped object.
An example from next.jdbc
: https://github.com/seancorfield/next-jdbc/blob/develop/src/next/jdbc/result_set.clj#L184-L200
I have a version of protocols that allow partial overriding with fallbacks to the parent classes - https://github.com/cnuernber/clojure/blob/faster-map/src/clj/clojure/core_deftype.clj#L600 The gist is to have the methodimplcache called from the method, and not go through the impl table. They are also faster for extend but that is another discussion. So at some point I will have a version of Clojure that does allow what you are talking about - I would term it partial overriding of methods of a baseclass or something like that.
I don't know if this is poking into the implementation details in a way that's not to be recommended, but you can call (:impls AProtocol)
and get a map of the current implementations of that protocol, then use merge
and extend
to update the impls? As in
(defprotocol TestFish
(one [this x])
(two [this x]))
(extend java.lang.String
TestFish
{:one (fn [this x] (str this :one x))
:two (fn [this x] (str this :two x))})
(extend-type java.lang.Long
TestFish
(one [this x] (+ this 1 x))
(two [this x] (+ this 2 x)))
(one "test" "test") ;; => "test:onetest"
(two "test" "test") ;; => "test:twotest"
(one 1 2) ;; => 4
(two 1 2) ;; => 5
(extend java.lang.String
TestFish
(merge (-> TestFish :impls (get java.lang.String))
{:one (fn [this x] (str this :other :one x))}))
(extend java.lang.Long
TestFish
(update (-> TestFish :impls (get java.lang.Long))
:two (fn [f] (fn [this x] (* 2 (f this x))))))
(one "test" "test") ;; => "test:other:onetest"
(two "test" "test") ;; => "test:twotest"
(one 1 2) ;; => 4
(two 1 2) ;; => 10
I'm sure it breaks in all kinds of cases, in horrible ways, but does it help?That replaces an existing implementation.
Whereas I need to duplicate an implementation for my own type and override/wrap one method.
It does sound possible with extend
and :impls
, but no clue whether there are any consequences w.r.t. e.g. tagging or something like that. And I'm certainly less interested in poking around the internals and more interested in writing code that I can safely forget about for a decade. :)
I think that extend
is totally supported - the bit I'm unsure about is calling :impls
on the protocol - but that seems to be how extend
works. I would have thought it would be easy enough to get all the functions for one type and merge in your own function for your new type. But yeah, totally see your point 😉
@U2FRKM4TW Do you have total control over the protocol? You could set :extend-via-metadata
and provide the wrapped methods in an object metadata.
Bummer
But I see exactly what you mean; even with metadata middleware I found myself wishing for something similar a few times.
"I need this things, buuuuuut I want to slightly change this method on-the-fly. All the other methods need to remain the same and be available."