Fork me on GitHub
#clojurescript
<
2023-02-14
>
hifumi12304:02:07

Is it considered undefined behavior to use extend-type to “override” a record’s implementation of a protocol method? Concretely

(defprotocol Foobar
  (foo [this])
  (bar [this]))

(defrecord Thing []
  Foobar
  (foo [this] "Called foo")
  (bar [this] "Called bar"))

(bar (->Thing)) ;=> "Called bar"

(extend-type Thing
  Foobar
  (bar [this] "Overloaded!"))

(bar (->Thing)) ;=> "Overloaded!"
(foo (->Thing)) ;=> "Called foo"
This is behaving how I want it to behave, but is it undefined behavior or a bad practice?

hiredman04:02:51

It would not surprise me if in some cases you got either behavior

hiredman04:02:28

Oh, pardon me, missed that this in #C03S1L9DN

hifumi12304:02:03

I just tried it in JVM Clojure and using extend-type this way indeed is an error, since under the hood the JVM disallows method implementations to be swapped in and out of classes

hifumi12304:02:10

That makes me want to believe this is UB, which is unfortunate because there’s a record implementing a protocol in a library and I want to override one method it implements

dnolen16:02:43

I would say that patching one fn in a protocol is not really well-defined, it probably won’t change but if this is critical code maybe I wouldn’t rely on it

Braden Shepherdson13:02:33

it seems unfortunate that the ^:export metadata only takes a boolean. I'd like to have conventional Lisp names in my CLJC code, but export them as (a) camelCase and (b) changing things like * and ? to Java-style prefixes like is. (defn ^{:export 'isSameThing} same-thing? [args] ...) I suppose that simply isn't supported. unless maybe shadow-cljs has magic for it?

thheller13:02:43

it takes a string

thheller13:02:05

(defn ^{:export "isSameThing"} ...)

Braden Shepherdson13:02:16

oh so it does work, but it's not well documented.

thheller13:02:30

at least I'm pretty sure it does 😛

Braden Shepherdson14:02:55

so yes and no. ^:export controls the .cljs.module.thisFunction export name. but in a shadow-cljs :npm-module the exports: {...} object uses the this_function snake case names.

thheller15:02:15

ah, :npm-module is a different story. I can change that

dnolen16:02:30

^:export is also sugar, (goog/exportSymbol …) or something like that

Braden Shepherdson17:02:35

@U05224H0W is that a change you're open to making? we don't need this urgently, but we're at the start of a big effort of porting JS business logic to CLJC.

thheller20:02:44

sure, open an issue on the shadow-cljs github please. I won't get to it tommorrow probably but should be easy fix soon