beginners

regibyte 2026-04-17T14:44:36.303339Z

I have a question for the language-designers out here, not sure if this is the correct channel to ask this, let me know if not I am working on a small clojure dialect in js out of curiosity, started with a classic tree walker interpreter, it worked, but was painfully slow, then I introduced an incremental compiler that compiles forms to js-closures, this worked well and made a lot of things much faster, however numeric computation combined with recursion is still a problem, a naive (fib 35) takes ~20 seconds in my runtime, which is… not great Now I’m talking to LLMs trying to understand what realistic options I have to make it faster, I know it will never be as fast as raw js, but I wanted to push it to the best it can be, so far only two approaches came to mind, both are possible, neither is easy: 1. Compile the source code to js directly (what clojurescript does) 2. Create a small bytecode VM Does anyone here have experience on either of these two paths and can advice me? I know both approaches require a lot of work to get right, that’s why I ask if anyone here has strong opinions/advices about this

dpsutton 2026-04-17T14:46:51.330569Z

have you tried (fib 35) in clojure? A naive implementation is a classic example of algo design

regibyte 2026-04-17T14:47:22.407539Z

Actually not really, let me try this real quick, I figured native clojure would be much faster anyway, will check now!

dpsutton 2026-04-17T14:47:39.482309Z

it’s not language execution speed that is the bottleneck

regibyte 2026-04-17T14:52:19.192029Z

(dotimes [_ 10] (time (fib 35)))
"Elapsed time: 1867.753 msecs"
"Elapsed time: 1729.861959 msecs"
"Elapsed time: 1724.8485 msecs"
"Elapsed time: 1720.11475 msecs"
"Elapsed time: 1781.608542 msecs"
"Elapsed time: 1804.215666 msecs"
"Elapsed time: 1854.636709 msecs"
"Elapsed time: 1814.996458 msecs"
"Elapsed time: 1721.787875 msecs"
"Elapsed time: 1912.959875 msecs"
Alright, so it seems like it takes about ~1870ms to run It’s not crazy fast, but also not unbearable

regibyte 2026-04-17T14:52:47.692599Z

> it’s not language execution speed that is the bottleneck Can you tell me more? with my limited knowledge, I’d say it’s the repeated structure interpretation that is slow

dpsutton 2026-04-17T14:53:11.316039Z

what’s the definition of fib you are using? i’m wondering how many recursive calls it makes. possible to make this have 35 calls or 2^35 calls

regibyte 2026-04-17T14:53:26.866039Z

(defn fib [n]
    (if (<= n 1)
      n
      (+ (fib (- n 1)) (fib (- n 2)))))
This one

dpsutton 2026-04-17T14:54:18.001579Z

(def call-count (atom 0))
(defn fib [n]
  (swap! call-count inc)
  (if (<= n 1)
    n
    (+ (fib (- n 1)) (fib (- n 2)))))
#'user/call-count
user=> 
#'user/fib
user=> (fib 35)
9227465
user=> @call-count
29860703

dpsutton 2026-04-17T14:54:26.824629Z

it’s a lot of work

regibyte 2026-04-17T14:54:52.058869Z

right! it is indeed

regibyte 2026-04-17T14:55:12.003659Z

So, fib is not the best comparison benchmark for this right?

dpsutton 2026-04-17T14:55:36.382809Z

it’s perhaps measuring other stuff

dpsutton 2026-04-17T14:55:45.763769Z

here are the callcounts per argument for fib 35

user=> @call-count
{0 5702887,
 7 514229,
 20 987,
 27 34,
 1 9227465,
 24 144,
 4 2178309,
 15 10946,
 21 610,
 31 5,
 32 3,
 33 2,
 13 28657,
 22 377,
 29 13,
 6 832040,
 28 21,
 25 89,
 34 1,
 17 4181,
 3 3524578,
 12 46368,
 2 5702887,
 23 233,
 35 1,
 19 1597,
 11 75025,
 9 196418,
 5 1346269,
 14 17711,
 26 55,
 16 6765,
 30 8,
 10 121393,
 18 2584,
 8 317811}

dpsutton 2026-04-17T14:56:07.761569Z

(fib 2) was computed 5.7 million times!

regibyte 2026-04-17T14:56:47.269159Z

Ahahaha yeah that is a lot, memoization would solve this, but that’s changing the algorithm and not the runtime

dpsutton 2026-04-17T14:56:49.250769Z

well maybe it is a good jump into your code, but it’s a pretty brutal metric to start with

dpsutton 2026-04-17T14:56:53.329949Z

exactly!

regibyte 2026-04-17T14:56:54.894139Z

Hummm interesting

dpsutton 2026-04-17T14:57:22.430209Z

the solutions to this are algo changes more than runtime changes. but you are seeing the benefits of the jvm inlining stuff most probably. So levels of optimization that are probably pretty far down your roadmap

👀 1
regibyte 2026-04-17T14:59:33.033679Z

Okay, yeah that clarifies things a bit, I should probably stop chasing this rabbit hole for now and come back when I have more knowledge

regibyte 2026-04-17T14:59:51.123939Z

Thanks a lot for the replies @dpsutton! I appreciate it gratitude

dpsutton 2026-04-17T15:00:14.782359Z

keep doing the project! it sounds super interesting and is just a cheat code to force learning a lot of stuff. ask questions! i enjoyed this as well

1
❤️ 1
seancorfield 2026-04-17T15:04:10.996889Z

Perhaps worth comparing with #squint to see what its raw compiled-to-js performance is...

👀 1
regibyte 2026-04-17T15:07:51.590699Z

Great suggestion!! I will do this today! it’s a good opportunity to learn more about squint

regibyte 2026-04-17T15:24:57.328939Z

Okay I’ve ran a small experiment here @seancorfield A lot of things became clear, the compiled-to-js approach beats my interpreter by a huge margin, and it’s understandable why Looking at https://squint-cljs.github.io/squint/ If you compile just

(defn fib [n]
    (if (<= n 1)
      n
      (+ (fib (- n 1)) (fib (- n 2)))))
You get this on the other side
globalThis.user = globalThis.user || {};
var fib = function (n) {
  if (n <= 1) {
    return n;
  } else {
    return globalThis.user.fib(n - 1) + globalThis.user.fib(n - 2);
  }
};
This is pretty much the exact same code that native js would run, the JIT can aggressively optimize this code, Whereas I’m paying the price for structure dispatch calls and fn applications per iteration + the boxed values allocated The speed diff shows the full story for (fib 35)
vanilla JS           avg: 0.088s 
 squint (compiled)    avg: 0.093s 
 my interpreter       avg: 19.0s 
Squint is pretty much on par with native js performance, I’m not even close 😅

seancorfield 2026-04-17T15:37:19.660589Z

Any sort of interpreter or VM you build on top of JS is going to run your language much slower than compiling to JS. But as a learning exercise, writing an interpreter, writing a VM, and writing a compiler to either intermediate code (for your VM) or directly to JS, are all good things to do...

🙏 2
regibyte 2026-04-17T15:43:52.336479Z

Yes this makes perfect sense, I’m learning a ton by building this, but still… it’s kinda hard for me to reconcile the fact that by going through the compiled route we kind of lose a lot of the dynamic properties of the runtime, you can’t just evaluate a user-provided string with a compiled code, load a file on the runtime, we lose the ability to introspect the environment at runtime because all the metadata is gone and to make it really fast like Squint’s approach, we also end up inheriting Js’s weird numeric handling, those unintended coercions start to appear at unexpected places… Anyway, this is just me learning about some hard truths, thanks a lot for taking the time to advice me @seancorfield 🙏 gratitude

seancorfield 2026-04-17T15:59:58.479039Z

Yeah, there's often a trade off between the language you're building and the target host semantics. In some situations that matters more than in others...

2026-04-17T16:05:27.779969Z

i don't have a ton of experience with pl design, but i would suggest Crafting Interpreters by Robert Nystrom, lead dev of Dart and all-around great dude

👀 1
2026-04-17T16:06:21.764109Z

sounds like you have roughly the first half of the book built (an AST-walking interpreter that is very slow) and then the second half he/you builds a bytecode vm

2026-04-17T16:06:56.518819Z

i don't think it'll answer this specific question for you, but it might expose you to some ideas for how to approach programming language creation/vm design

regibyte 2026-04-17T16:10:56.845949Z

Now that’s awesome! I will definitely get my hands on this book! Dart is an awesome language Yeah the original question was just to get started talking, I still need to understand what the VM implementation looks like in practice, the book will probably show me something I can use!! Tks for the recommendation!

liebs 2026-04-17T17:25:26.859389Z

I happen to be working on a vaguely similar project (compiling Lisp to JS) in Scheme rn and perhaps you would be interested to read this https://www.gnu.org/software/guile/manual/html_node/Compiler-Tower.html @reginaldo.junior696

regibyte 2026-04-17T17:30:18.250099Z

Nice!! I have never seen this before, great material @bhlieberman93!! First time hearing about guile too At first sight, this seems more advanced than what I currently understand, will take some time to read it carefully, appreciate you sharing 🙏

liebs 2026-04-17T17:31:31.004069Z

it's somewhat over my head as well, but I am gradually figuring it out. Guile is an awesome language.