Readit News logoReadit News
tekkk commented on CRDT: Text Buffer   madebyevan.com/algos/crdt... · Posted by u/skadamat
josephg · 4 days ago
The thing that can make real world text CRDT implementations complex is that the optimisations kinda bleed into all the rest of your code. The 2 big optimisations you want for most text CRDTs - including egwalker - are:

- Using a b-tree instead of an array to store data

- Use internal run-length encoding. Humans usually type in runs of characters. So store runs of operations instead of individual operations. (Eg {insert "abc", pos 0} instead of [{insert "a", pos 0}, {insert "b" pos 1}, {insert "c" pos 2}]).

But these two ideas also affect one another. Its not enough to just use a b-tree. You need a b-tree which also stores runs. And you also need to be able to insert in the middle of a run. And so on. You need some custom collections.

If you do run-length encoding properly, all iteration throughout your code needs to make use of the compressed runs. If any part of the code works character-by-character, it'll become a bottleneck. Oh and did I mention that it works even better if you use columnar encoding, and break the data up into a bunch of small arrays? Yeahhhh.

So thats why diamond types - my optimized egwalker implementation - is tens of thousands of lines of code instead of a few hundred. (Though in my defence, it also includes custom binary serialization, testing, wasm bindings, and so on.)

Rust makes the implementation way easier to implement thanks to traits. I have simple traits for data that can be losslessly compressed into runs[1]. A whole bunch of code takes advantage of that, by providing tooling that can work with a wide variety of actual data. For example, I have a custom vec wrapper that automatically compresses items when you call push(). I have a "zip" iterator which glues together other iterators over run-length encoded data. And so on. Its great.

Though now that I think about it, maybe all that trait foo is what makes it headache inducing. I swear its worth it.

[1] Eg MergableSpan: https://github.com/josephg/diamond-types/blob/00f722d6ebdc9f...

tekkk · 4 days ago
Jeezs. Thanks for the breakdown. I suppose the layering of different, complicated patterns make it too thick to parse. And some of the CRDT APIs leak quite a bit of complexity once you want to do something a little more complicated eg wrap rich text editor content.
tekkk commented on CRDT: Text Buffer   madebyevan.com/algos/crdt... · Posted by u/skadamat
josephg · 5 days ago
I invented it, so personally I like it very much.

The big benefit of eg-walker is that you don't need to load any history from disk to be able to do collaborative editing. There's no need to keep around and load the whole history of a document to be able to merge changes and send edits to other peers. Its also much faster in most editing situations - though modern optimizations mean text based CRDTs are crazy fast now anyway.

The downside is that eg-walker is more complex to implement. Compare - this "from scratch" traditional CRDT implementation of FugueMax:

https://github.com/josephg/crdt-from-scratch/blob/master/crd...

With the same ordering algorithm implemented on top of egwalker:

https://github.com/josephg/egwalker-from-scratch/blob/master...

Eg-walker takes about twice as much code. In this case, ~600 lines instead of 300. Its more complex, but its not crazy. It also embeds a traditional CRDT inside the algorithm. If you want to understand eg-walker, you should start with fuguemax anyway.

tekkk · 5 days ago
Wow. Didnt know there were these CRDT examples for mere mortals. I supppose once you put Rust in the mix the heads start to explode, mine included. Cool!
tekkk commented on Show HN: Bolt – A super-fast, statically-typed scripting language written in C   github.com/Beariish/bolt... · Posted by u/beariish
tekkk · 14 days ago
Really impressive, great job! I was interested to see how you had solved Result type and that seems quite developer-friendly—no wrappers just value & error union. I should try it out to see how it's to write if I can run it on ARM64. I wish Godot Script looked like this.
tekkk commented on Lina Khan points to Figma IPO as vindication of M&A scrutiny   techcrunch.com/2025/08/02... · Posted by u/bingden
ptero · 22 days ago
Yes. But Google being Google it got top notch planning advice from world class auction experts that Goldman pulled in to advise them on the IPO.

Most companies without such expert advice could step into some pitfalls. Just a guess, I am not an expert, but if my company were doing an IPO I would prefer it not to play financial games to eke out a percent of IPO price and instead focus on long term price stability to become a solid stock. My 2c.

tekkk · 22 days ago
Figma's stock quadripled in price from 33 to whatever it is now. Not saying it's good or bad, just that those gains must have been nice with effort akin to staring spreadsheets a while and babbling in meetings.
tekkk commented on Why Elixir? Common misconceptions   matthewsinclair.com/blog/... · Posted by u/ahamez
rubyn00bie · a month ago
Lmao. This has to be the funniest comment I’ve ever read on here. I can assure you, the only copium being huffed is by you, mate. I have written Scala, Swift, Java, and more (including TypeScript). I have zero trouble with type systems, but I have wasted enough time fighting them for little real world benefit. In Elixir, and this is the best part, I don’t fight type bugs. You probably do because type erasure means you can still have them if someone has mistyped something or shit on something at runtime— the joys of JavaScript.

It sounds like you’re really trying to justify something and that’s great for you. I’m really happy for you. Keep it up. May you soar where no junior dev has dared to soar before. God speed.

tekkk · a month ago
Hah. Sure buddy, Mr. Sr Dev. Sorry if I offended you and your vast experience. Without types there definitely aren't type bugs, I grant you that, and JVM languages are quite different to TS. I don't know if your argument on type erasure is any better than advocating for dynamic typing but it definitely happens when you just start throwing anys.

And look, I'm first to admit that TS type system isn't perfect (and it can cause some devs to go overboard) but I have read my share of Python scripts that were read-only from the minute they were born.

  It sounds like you’re really trying to justify something and that’s great for you. I’m really happy for you. Keep it up. May you soar where no junior dev has dared to soar before. God speed.
And please, your condescension just sounds insecurity to me. It's highly amusing though that you try to play me down as a silly junior dev, I'm quite satisfied that my original assessment was correct.

tekkk commented on Why Elixir? Common misconceptions   matthewsinclair.com/blog/... · Posted by u/ahamez
rubyn00bie · a month ago
I’d recommend it. I used to think I needed statically typed languages to write sound code, but after enough time with Elixir (10 years professionally and going) I really don’t believe that to be true… A huge portion of my change of heart is due to Elixir (and Erlang) being functional and only having a handful of types:

atom, binary, boolean, function, list, map, pid, reference, integer, float, and tuple

There are a few others but they are generally special cases of the ones above. Having so few data types tends to make it much more obvious what you’re working with and what operations are available. Additionally, because behavior is completely separate from data it’s infinitely easier to know what you can and can’t do with a given value.

Ruby being dynamic drove me insane at times, but Elixir/Erlang being dynamic has been a boon to productivity and quality of life. I recently had to write some TypeScript and was losing my mind fighting the compiler, even though I knew at runtime everything would be fine. Eventually I slathered enough “any” on to make the burning stop… But! That’s something I haven’t had to do in years, and it was 100% due to type system chicanery and not preventing a bug or making the underlying code more sound.

There are still some occasions where having some static typing would be nice— but they’re pretty rare and often only for things that are extremely critical or expensive to fix. And IMHO even in those cases, Elixir’s clarity and lack of (implicit) state generally make up for it.

tekkk · a month ago
Here's my take as TS dev. You just never learned to use types in the first place where there is very little ambiguity on any types anywhere because there is close to no any's used. Sounds like you guys get high and mighty on your tunnel-visioned copium—I mean I used to write JS for god's sake and thought it was okay. And I remember when I first tried TS felt annoyingly hampered by having to actually use interfaces properly.

Sure, the nature of Elixir probably makes it easier but I find little joy in dynamic whack-a-mole and mental gymnastics to infer types instead of fricking actually being able to see them immediately.

I could go commando in TS as well and switch to JS and JSDoc, leaving everything gradually typed and probably be fine but I'd feel terribly sorry for anyone else reading that code afterwards. It'd be especially silly since I can now just infer my auto-generated Postgres zod schemas with little effort. Moreover, a good type system basically eliminates typing-related bugs which you guys apparently still have.

So please, don't over-generalize just because you think you got it figured out.

tekkk commented on Why you should choose HTMX for your next web-based side project (2024)   hamy.xyz/blog/2024-02_htm... · Posted by u/kugurerdem
tekkk · a month ago
I got a wave of shudder reading the acronym "HAM stack". Yugh. MEAN, MERN, RERN–once hyped up hot air which now sounds so dated and hackneyed. It's cool to be excited about tech but if your main selling point is building "faster and cheaper", I don't know if picking up a minimalistic framework you know nothing about is faster than just re-using your trusty boilerplate.

Be it React or Svelte or whatever. With serverless backend if you want to keep costs down. Although a server from Hetzner isn't that expensive and you can host multiple APIs there.

tekkk commented on Bun adds pnpm-style isolated installation mode   github.com/oven-sh/bun/pu... · Posted by u/nateb2022
tekkk · a month ago
So can I use bun now in pnpm monorepo without problems? I like bun and want to try it out more but also, I don't want to do the hassle of migrating only to find out some functionalities are missing eg. ability to run specific scripts on specific packages in monorepo.
tekkk commented on Async Queue – One of my favorite programming interview questions   davidgomes.com/async-queu... · Posted by u/davidgomes
tekkk · 2 months ago
Heh heh. I dont understand what the fuss is about, AsyncQueue is kinda cool in JS. I use it, from time to time, to implement async generators that can be iterated over with for await.

Although my implementation doesnt have any sequencing as never had need for it but, more importantly, it has retrying and timeouts. Well retrying I might have implemented on level higher.

Maybe I'm just one of the rare few who actually would have enjoyed this type of question as a chance to brag about my version. Kinda neat as I've never been interested in programming challenges to, for once, know exactly the solution.

tekkk · 2 months ago
While I'm at it, here's my version, if people want to see and give feedback:

  export interface AsyncQueueOptions {
    timeoutSeconds?: number
  }

  export class AsyncQueue<T> {
    private readonly queue: Promise<T | undefined>[] = []
    readonly timeoutSeconds: number
    private timeout: ReturnType<typeof setTimeout> | undefined
    private reject = () => {}
    private resolve = (value: T | PromiseLike<T>) => {}

    /**
     * @param timeoutSeconds @default 25
     */
    constructor({ timeoutSeconds = 25 }: AsyncQueueOptions = {}) {
      this.timeoutSeconds = timeoutSeconds
      if (timeoutSeconds > 100) {
        console.warn(`You are initializing AsyncQueue with over 100s timeout: ${timeoutSeconds}`)
      }
      this.queue.push(
        new Promise<T | undefined>((resolve, reject) => {
          this.resolve = resolve
          this.reject = reject
          this.timeout = setTimeout(() => resolve(undefined), timeoutSeconds * 1000)
        })
      )
    }

    next(): Promise<T | undefined> | undefined {
      return this.queue.shift()
    }

    push(msg: T) {
      this.resolve(msg)
      this.queue.push(
        new Promise<T | undefined>((resolve, reject) => {
          this.resolve = resolve
          this.reject = reject
          clearTimeout(this.timeout)
          this.timeout = setTimeout(() => resolve(undefined), this.timeoutSeconds * 1000)
        })
      )
    }

    close(msg?: T) {
      if (msg) {
        this.resolve(msg)
      }
      clearTimeout(this.timeout)
    }
  }

tekkk commented on Async Queue – One of my favorite programming interview questions   davidgomes.com/async-queu... · Posted by u/davidgomes
tekkk · 2 months ago
Heh heh. I dont understand what the fuss is about, AsyncQueue is kinda cool in JS. I use it, from time to time, to implement async generators that can be iterated over with for await.

Although my implementation doesnt have any sequencing as never had need for it but, more importantly, it has retrying and timeouts. Well retrying I might have implemented on level higher.

Maybe I'm just one of the rare few who actually would have enjoyed this type of question as a chance to brag about my version. Kinda neat as I've never been interested in programming challenges to, for once, know exactly the solution.

u/tekkk

KarmaCake day1686March 3, 2017
About
goto.tekk@gmail.com
View Original