sci

jyn 2025-09-14T15:41:04.062529Z

I want to add first class support for monkey patching in my guest VM. I found :load-fn, but it works purely on strings, and I don’t see a hook to overwrite the SCI state after that function is run. how do you recommend I do this? Should I override require or something like that? I do always have the option to just append the string of the patch code after the string of the loaded file, since clojure allows overriding defs in source, but I’m not sure if that’s reliable in all cases.

✅ 1
borkdude 2025-09-14T15:44:38.551629Z

Monkey patching as in changing vars? You can do this in the same way as Clojure using alter-var-root

jyn 2025-09-14T15:57:07.970189Z

hm, to be clear, i want to have something like a patches directory that can override the behavior of require, i don’t want to modify the call sites of require

jyn 2025-09-14T15:57:21.821049Z

if i could then alter-var-root would work, yes

borkdude 2025-09-14T16:00:37.721839Z

Do you just want to load everything from patches at startup?

borkdude 2025-09-14T16:01:11.154429Z

Like several scripts sequentially or can they depend on one another?

jyn 2025-09-14T16:01:28.081649Z

that could work. it has different semantic behavior, right? i’m no longer loading things lazily, so some errors will always show up where they wouldn’t have before?

jyn 2025-09-14T16:01:53.683799Z

they can depend on each other, just like a normal clojure program

jyn 2025-09-14T16:04:29.899519Z

my ideal solution for this would be a hook that runs after each require, but I understand that’s kind of weird and niche for my use case lol

borkdude 2025-09-14T16:19:40.693809Z

so patches is basically your classpath right? and you have built-in namespaces that people can override or so? can you sketch out a scenario of what you would like to happen when a user does something?

jyn 2025-09-14T17:20:23.929559Z

yeah, let me talk about the whole design. flower is a static site generator that is a library and not a framework. that means that all the things people expect from a framework, like inversion of control ("just write an .md file and run build") and custom markdown footnote rendering are done in "user-space" (the SCI guest environment, not the Graal binary). i ship that userspace in a hidden .defaults folder and allow you to override it. for example, markdown footnotes are done in .defaults/transformers/markdown.clj and you can override it by creating your own transformers/markdown.clj in the top-level directory. that works! but it requires file-level granularity: if anything in the default markdown.clj changes, you don't see those changes (or you have to resolve conflicts). i would like to get it down to def-level granularity: people can override just the transformers.markdown/renderers passed to md->hiccup, without having to copy-paste the whole defaults file. to do that i had the idea to let them write patches/transformers/markdown.clj which is patched into the existing defaults by running alter-var-root for each variable defined. the problem is that there is no place i can insert alter-var-root: if i do it before returning from :load-fn, the namespace doesn't exist yet, and there is not a hook to do it after. i am asking for a hook to do it after.

jyn 2025-09-14T17:23:17.586969Z

this is why i was considering just doing a string-append in load-fn, because i don’t think SCI has anything like this currently and i feel bad asking for a feature just for me 😅

borkdude 2025-09-14T18:14:06.803639Z

> i would like to get it down to def-level granularity: people can override just the transformers.markdown/renderers passed to md->hiccup Yes, you could just load the original file + append the patches. Or if the original file is already loaded, then you could just only load the patch file

borkdude 2025-09-14T18:24:52.696379Z

so in :load-fn you could return the proper namespace source + appended patch

👍 1
jyn 2025-09-14T19:09:44.943509Z

that works :) thank you!

👍 1