Fork me on GitHub
Daniel Stephens09:02:40

Hi 👋 I started messing around with some changes to get reify+defrecord to work with (java) interfaces. Tbh it was mostly just a learning experience for how things worked, which was successful, but I just wondered how viable this idea would be in reality. Basically it takes a class and uses some minimal reflection to get the methods from the class, and turns those into a defprotocol form. Eventually I was thinking it would be possible to do this at the start of a script for all interfaces in :classes of env. It definitely doesn't work for cljs currently and I'm not sure if it would work with graal, but wondering if it could be extended to do so?

Daniel Stephens09:02:37

it works mostly! (the dot forms .read aren't right yet, but I think I could fix this up)

  "(class->protocol java.lang.Readable)
  (defrecord Something [] java.lang.Readable (read [_ cb] 1))
  (read (Something.) 2)"
  {:classes {'java.lang.Readable java.lang.Readable}})
=> 1

  "(class->protocol java.lang.Readable)
  (read (reify java.lang.Readable (read [_ cb] 1)) 2)"
  {:classes {'java.lang.Readable java.lang.Readable}})
=> 1


@ULNRSUK8C The main problem with supporting Java classes in defrecords is when these records are passed to Java methods. If they are not really implementing those types, then you cannot fool the Java methods


In reify they are already supported, but we have to generate a permutation of all interfaces beforehand, to circumvent bytecode compilation. This is done in babashka

👍 3
Daniel Stephens09:02:26

ahh okay, that makes sense! I'll do some testing around the java interop with the records but I see why it wouldn't work. Thanks for your insight!


I guess we could support it if we made the result of defrecord something we reified the same as with reify and then implement the ILookup, etc interfaces ourselves, maybe.


But one other challenge is to support a combination of reified Java interfaces and sci protocol methods, which is also currently not supported

Daniel Stephens09:02:52

yeah, that's what I was sort of trying to mess around and get with this, right now I can get a mix of "classes" and protocols, but really it's just that they are all protocols. It's been an interesting ride though!

Daniel Stephens20:02:58

spent some more time messing around with this, might have something more viable. Basically sets up a reified IReified object as well and uses that as another class, so then you can get a combination of protocols and classes. Needs simplifying I expect, but if this makes sense I could add IReified into that 'combinations map' in babashka 🙂


Looks promising :) I'll play around with it. Did you test it with babashka master?


as in running script/test on babashka master with this sci PR


So all "reified" objects are a sci.imp.types.IReified (which then dispatches to protocols) AND optionally other Java interfaces. Yeah, that might work :-D Coool :)

Daniel Stephens22:02:36

Had to run off after posting, sorry. Glad it sounds okay to you! Thanks for making the PR, when I get a chance I'll take a look at the tests, I don't think I have a great setup currently, so haven't figured how to point my babshka source at the edited sci repo, will take some time to look into that.


@ULNRSUK8C I think you can git clone babashka recursively git clone ... --recursive and then change the deps.edn :local/root for sci to point at your fork

👍 3

and then run with clojure -M:main -e whatever.clj


or, you can go into the sci submodule and check out your fork there


that's how I usually do it

Daniel Stephens22:02:34

ahh sweet, doesn't sound like too much involved, will have a look in the week 👍 cheers, goodnight for now 👋