This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-20
Channels
- # admin-announcements (1)
- # announcements (1)
- # beginners (115)
- # calva (31)
- # cider (25)
- # clj-kondo (47)
- # cljdoc (23)
- # cljs-dev (5)
- # clojars (1)
- # clojure (60)
- # clojure-australia (1)
- # clojure-europe (23)
- # clojure-nl (3)
- # clojure-norway (2)
- # clojure-spec (3)
- # clojure-uk (18)
- # clojurescript (49)
- # community-development (1)
- # cursive (4)
- # datahike (2)
- # datascript (3)
- # datomic (36)
- # deps-new (2)
- # emacs (2)
- # events (9)
- # fulcro (6)
- # graphql (2)
- # gratitude (13)
- # holy-lambda (1)
- # introduce-yourself (10)
- # macro (2)
- # malli (5)
- # meander (9)
- # news-and-articles (5)
- # nextjournal (1)
- # off-topic (32)
- # pathom (17)
- # pedestal (13)
- # polylith (4)
- # protojure (4)
- # reagent (4)
- # sci (27)
- # shadow-cljs (2)
- # show-and-tell (2)
- # specter (3)
- # tools-deps (7)
- # xtdb (16)
I finally got around to packaging the ability to patch protocols to work with both sci values and "outside" values and allow for extension within sci. Is that something that might be a good fit to pull into sci itself? If it does, I can work on a pull request. Otherwise, I'll probably release it in a standalone library. example usage:
(def opts
{:namespaces
(merge (do
(scify/scify-ns-protocols 'membrane.ui)
(scify/ns->ns-map 'membrane.ui))
(scify/ns->ns-map 'membrane.component))})
scify/ns->ns-map
creates a map from an existing ns for use in sci
scify/scify-ns-protocols
will replace protocols with versions that work inside and outside of sci and allow for extension. idempotent.
code: https://github.com/phronmophobic/mobiletest/blob/main/src/com/phronemophobic/mobiletest/scify.cljOK, so you are patching the original protocol vars. Nice! Just curious, does that also work with direct linking?
It does!
tbh, I'm not exactly sure why. maybe it's because defprotocol
uses intern
to create the protocol method vars?
That surprises me. What if you have a library which calls a protocol function like (defn library-fn [] (proto-fn :bar))
and you patch the var, and then your SCI program implements this protocol function on some type that wasn't implement before, I would expect that library-fn
wouldn't be affected by this, with direct linking?
then again, I'm not completely sure, perhaps protocol vars aren't prone to direct linking
I think it's that protocol vars aren't directly linked
otherwise, you couldn't patch it in the first place
ah you are patching the protocol var, but not the vars that represent the functions, right?
I'm altering the meta for the protocol itself, but not its value
all the protocol methods get patched though
altering the protocol's meta is really only for bookkeeping:
• patch only once
• mark patched protocols for ns->ns-map
yeah, it seems like direct linking doesn't affect protocol vars:
$ clj -J-Dclojure.compiler.direct-linking=true
Clojure 1.10.1
user=> (defn foo [] :foo)
#'user/foo
user=> (defn bar [] (foo))
#'user/bar
user=> (bar)
:foo
user=> (defn foo [] :bar)
#'user/foo
user=> (bar)
:foo
user=> (defprotocol Foo (pfoo [this]))
Foo
user=> (defn libfn [x] (pfoo x))
#'user/libfn
user=> (extend-protocol Foo String (pfoo [_] :dude))
nil
user=> (libfn "hello")
:dude
user=> (:method-builders Foo)
{#'user/pfoo #object[user$eval152$fn__153 0x3157e4c0 "user$eval152$fn__153@3157e4c0"]}
user=> (alter-var-root #'user/pfoo (fn [old] (fn [this] (prn :this) (old this))))
#object[user$eval178$fn__179$fn__180 0x18eec010 "user$eval178$fn__179$fn__180@18eec010"]
user=> (libfn "hello")
:this
:dude
user=> user/pfoo
#object[user$eval152$fn__153$G__143__158 0x26f7cdf8 "user$eval152$fn__153$G__143__158@26f7cdf8"]
user=> (extend-protocol Foo clojure.lang.Keyword (pfoo [_] :num))
nil
user=> user/pfoo
#object[user$eval152$fn__153$G__143__158 0x35dd9ed3 "user$eval152$fn__153$G__143__158@35dd9ed3"]
It seems the hash/memory location (what is this again?) changes but not the object itself?
it's not totally clear to me how it works. > Additionally, the compiler can remove unused vars from class initialization and direct linking will make many more vars unused. https://clojure.org/reference/compilation#directlinking My best guess is that however protocols are implemented causes the vars to used and included when compiled
It might be good to verify this in http://ask.clojure.org wether we can rely on this
ok, asking now
https://ask.clojure.org/index.php/10967/are-protocol-methods-guaranteed-to-not-be-directly-linked
we got an answer. what do you think?
Yeah, I think it's good to rely on the state of the Clojure compiler for now that it won't be directly linked. Your solution relies on SCI building protocols on multi-methods which also isn't guaranteed to stay the same (it's an impl detail which happened to work very well with native image) but may change in the future (e.g. when GraalvM exposes other ways to accomplish the same thing) - also not very likely but still. So for now, I think it's good to use this code perhaps in a lib, but not yet as part of the SCI API. We can however add it in the documentation or wiki in a tips and tricks section.