72 comments

  • drzaiusx11 a day ago ago

    I recently performed this exact exercise of converting a complex library set from one language into an intermediate state machine representation and then translated into N other languages. It worked well but there's a lot of caveats. I'd highly recommend a direct "port" in most cases tbh, as many bugs are "load bearing" and may not survive the intermediate translation. I speak from experience.

    • aka-rider a day ago ago

      > I'd highly recommend a direct "port"

      I'm sure there are other caveats. Also cost of the more or less straightforward Bun port was $165000 for 500KLoC.

      • drzaiusx11 a day ago ago

        Are you implying a direct bug for bug port is more expensive than converting to an intermediate representation and then converting via generators? Depending on the "fidelity" of the representation I'd figure the costs are about the same.

        • aka-rider a day ago ago

          My understanding is, direct port is more expensive besides toy projects of course, looking at Bun and also listening to people who've done a few language conversions, they extract something first.

          If not an intermediate representation, my first question would be: how to split the work. You cannot just prompt full rewrite of 60K LoC, you cannot do it module by module — modules do translate 1:1, like in my case golang packages did not matched Rust crates. Bun did file by file.

          With hierarchical state machines in the middle, I did it almost in one shot.

    • dilyevsky a day ago ago

      Wouldn’t finding such bugs be considered advantageous? That is unless someone just yoloing the result directly to customer ofc

  • aka-rider 2 days ago ago

    Following the recent "Rewriting bun in Rust" I thought to run an experiment which turned out to be success.

    • onion2k a day ago ago

      Porting something to a language you don't know doesn't seem very helpful to me. You've locked yourself out of doing useful work except with continued application of more AI. Without the ability to verify it, except with even more AI maybe, you're starting on a slippy slope to slop.

      If the experiment was "spend 400 bucks to see if it'll work" then that's awesome, and fun, and a cool use of AI. It's impressive that AI can do that.

      If it was to make something useful ... has it?

      • aka-rider a day ago ago

        You are correct, that this is not the best Rust learning material.

        $400 are subsidized into the subscription, and this was mainly an experiment to prove the theory about data conversion step. I call it a success and I use rune editor daily.

        To me, running multiple agents is not very different from managing multiple teams — I won't be able to keep up with the changes by reading the code.

        I may make certain architectural decision, and I need to act based on some signals.

        The simplest example is clusters of bugs are signaling that certain modules are dirty. Sometimes I read a plan and understand that the agent is trying to workaround some auwful engineering.

      • qazxcvbnmlp a day ago ago

        I work on a C++ codebase. I frequently prototype in c and then have the ai model slopify it back to c++. Nice b/c I am faster at reading c, but hard b/c you miss some of the features/nuances of c++.

        • aka-rider a day ago ago

          I would be afraid to do this with C++.

          My friend once sent me a snippet, maybe 10 lines of C+++, asking "can you spot the UB?".

          So I'm staring at these 10 lines, I KNOW there is an UB. I wasn't able to find it without a hint.

          • tstenner a day ago ago

            Was it the one with the elided null check?

            • aka-rider a day ago ago

              I don't remember the details, roughly it was unexpected invocation of move semantic, causing use after free in a loop.

              My all-time favourite example is (again, my memory, I may be a bit wrong):

                  for (int i = 0; i < (size_t)limit; ++i) {
                  }
              
              at some point limit could potentially become greater than INT_MAX, the compiler decided that i<limit could never be true because that would cause signed int overflow which is UB, so it "optimized" the loop into

                 while(true)
              
              signed unsigned mismatch makes me shiver
              • dgrunwald 19 hours ago ago

                The compiler cannot optimize that into `while(true)` because the original code does not encounter undefined behavior when `limit` is small enough to fit into `int`. What it can do: infer that `limit <= INT_MAX` and use that to optimize the code following after the loop (and in some cases, even the code before the loop).

                • aka-rider 19 hours ago ago

                  This isn't complete example. I don't remember the details unfortunately.

                  But somehow compiler has decided that i <= limit is always true.

        • itemize123 a day ago ago

          interesting, c -> c++ transition should be smooth though

    • coder-pm a day ago ago

      How much did the verification cost on top? how did you gate it? was it a Go test suite you ran against the Rust or what? I always wonder how ppl are testing these rewrites, rewriting the tests can also lead to bug. I really wonder how reliable are rewrites like that, a 65k lines you didn't actually read. How did you confirm the semantic equivalence, same behaviour?

      • aka-rider a day ago ago

        All very good questions.

        Agents are actively destroy QA gates in many ways, usually by cheating ("the test is buggy, not my changes" — changes the test), or just rot QA slowly by writing buggy overcomplicated tests

        What works for me 10/10 is fuzzing and my own constant usage. For this project specifically (text editor), I asked LLM to create human-like fuzzing session, it sends keystrokes like: "the user is searching for a file, editing, <ordering a lizard>, saves changes".

        On top of it, I run https://mutants.rs/ which is kind of tests fuzzing. It flips random switches in the app itself, and if tests are silent - they missed a bug.

        The downside of this, is I usually find bugs after 1-2 hours of running. I use local Qwen to babysit these sessions, to make initial investigation, a repro case, and file a ticket.

        • metaltyphoon a day ago ago

          Why are you just pasting LLM answers :(? I see this constantly in Slack DMs to every day from work. It hurts

          • tensegrist a day ago ago

            this is not llm writing. there's no need to startle at the sight of an em-dash

          • aka-rider a day ago ago

            This is genuinely how I write :'(

            It is probably because I read tons and tons of LLM output.

            • orwin a day ago ago

              It's ok, it is slightly llm-like but not in the worst way, like it was edited after. You aren't Claude at least.

              • aka-rider a day ago ago

                >You aren't Claude at least.

                I absorbed so many different models at this point :)

                Thank you for the kind words.

      • aka-rider a day ago ago

        I realized that I haven't answered the question. These $400 also include the tests. Fable ported "human fuzzing session" (the best bug hunter) from Go to Rust and used it to validate everything else. I used hierarchical state machines, so a lot of my QA gates were encoded into the implementation — impossible states are, well, impossible.

        (I ported first 80% practically in one shot, planning and then leaving Fable overnight to orchestrate). Then I added a bunch of features, so at the end I ported more like 150% of the original code, I added tree-sitter, and a bunch of syntaxes highlighters. At the end with all that, price went up to ~$650

        • coder-pm a day ago ago

          This is impressive but it again led me to questions. Porting the fuzzer from Go to Rust to validate Rust is a bit circular, isn’t it^^? Porting a fuzzer bug will hide the same class bug in the code it’s checking, who fuzzes the fuzzer / setup / harness:)? A good standard for rewrites is a differential testing, feed the same input to the old Go app and the new Rust then diff the outputs. Did you do that?

          • aka-rider a day ago ago

            >feed the same input to the old Go app and the new Rust then diff the outputs.

            Yes, I completely forgot to mention, this is exactly my case. Rune is a TUI editor, so I feeded the same terminal sequences to the old and new apps.

            It didn't translate 1:1 (I ported core editor first, there were side panels, and different chrome elements) so I instructed LLM to use ttyd (tty -> browser render), Fable then could open both apps with playwright, make and compare screenshots.

            To rephrase, one critical component is to establish a feedback loop for the model. This new generation of models: Opus 5, Fable, GLM-5.2, even Qwen3.8-27B can self-correct, provided they know whether they are progressing or not.

            A month ago, especially smaller model would fall into a rabbit hole it dug for itself and would never recover. This generation can sometimes run tens of hours without losing track.

            I still wouldn't trust a model after 70% context window, but the progress is noticeable.

            • coder-pm 20 hours ago ago

              The ttyd and playwright is a clever differential way, personally I’m doing the same when it’s about to compare the views (or fix something related to rendering). Good job on that!

              A TUI editor’s real output is the bytes stored on disk, while rendering can look identical the saved files might diverge (encoding, line endings, trailing new lines etc). Did you manage to diff that?

              Totally agree on the overnight roadmap runs I have the same experience here. The agents have to know how to self-correct and if it’s progressing, otherwise it’s failing!

              • aka-rider 18 hours ago ago

                >files might diverge

                The way rune works with files minimizes chances of silent corruption. I keep original byte blobs immutable, separately there is a journal (kinda WAL) of positional deltas (inserts and deletes).

                So I only need to validate that blob + deltas = snapshot.

                Disk IO is encapsulated through VFS, and writes are atomics (write to a temp file, then rename).

                Separate virtual rendering buffer is built on top of that. Rune, like Obsidian, renders markdown preview inline, so the same chunk could be rendered as "Header" as well as `## Header` when under the cursor.

                All of that makes it quite easy to work with text. The core function is to translate offset in a byte array to line and column and back, which is pure math and relatively easy to test.

                Another trick that helped a lot is to use sqlite extensively: blobs, deltas, vfs, redo and undo history graph are all sqlite tables.

                I noticed that LLMs make stupid decisions when it comes to data structures, but they understand CRUD and SQL, so I turned all Rune's internals into dumb CRUD.

                • coder-pm 17 hours ago ago

                  Nice trick with the structures, good for agent legibility! I will try it out on the right occasion:)

      • doc_ick a day ago ago

        Well the author “cannot simply dye my hair blue” so maybe they can’t confirm semantic equivalence or behavior? Poke aside (and unserious intro?) seems like a general and loose question of if the conversion can happen.

        *be me over eager

        • aka-rider a day ago ago

          I consider a wig. I'm still on a fence with Rust at this point. see comments above

          • doc_ick 4 hours ago ago

            Llm rewrite or llm boosted dev aside, I’m still on the fence about rust too. My main issue is deployment as I hop different os’s casually and makes rust a non-starter.

  • kuratkull 18 hours ago ago

    I have rewritten several things from eg. Python to Rust, Rust to Go very recently. The 400 USD is pretty arbitrary as you could rewrite several big projects pretty comfortably with the Claude ~100 USD subscription tier.

    In my experience it mostly comes down to the harness (or lack of) that you use. Something like 'superpowers' can be pretty verbose and hash out things for a long time (and use a decent amount of tokens) but the output is pretty decent. The better instructions and the more brainstorming you do initially the better - as the subagents encounter fewer issues.

    Without a harness you could try a direct port (prompt: 'convert x to y, don't bother me') and if the languages are roughly compatible you could get a seemingly working port much quicker but likely with major hidden issues. A comprehensive testsuite is obviously a must.

    • aka-rider 16 hours ago ago

      > I have rewritten several things from eg. Python to Rust, Rust to Go very recently.

      What is the scale? Because I'm pretty sure it's impossible to one shot 65k LoC with "good luck, make no mistakes" prompt.

      I also did this within a subscription. I counted the number of tokens afterwards and calculated the cost as if I'm paying per token. $400 is of course arbitrary, but it's a ballpark number, bun was $165000.

      > In my experience it mostly comes down to the harness (or lack of) that you use.

      Yep, it is.

      Tokens per task is a good proxy measure of skills, 'superpowers' or any other.

      Either a skill gets you the thing more efficiently (less tokens), or you don't need to redo the result afterwards (less tokens). I benchmark all my skills that way.

      Models need less and less steering at this point, especially frontier ones.

  • never_inline 21 hours ago ago

    Most important information is missing here.

      * How many lines was the result? Considering how much err != nil and line splitting needs to be done in Go, did you at least reach 30k SLoC?
        * How was sloc counted here? includes comments, blank lines or not? (something like cloc will give a good answer).
      * Performance characteristics of resulting rust, was there an improvement? It maybe appealing to say Rust is Always faster than Go.
    
    As usual these AI coding posts tend to be loose on actual measurements. Don't like it. Granted you can't do too much experimentation with prompting techniques since you're paying per token. But at least you can assess the code that was produced?
    • aka-rider 20 hours ago ago

      Thanks for the feedback. My main goal was to present the idea with an intermediate representation, I didn't payed much attention to the specifics of this translation, it would vary wildly depending on code bases.

      65k LoC of Go without comments resulted in roughly 60k LoC of Rust witout comments (code column of the cloc tool).

      The error handling is not so different between Rust and Go, in both cases I cannot panic to avoid the data loss. So it boils down to if (failure) return something for graceful degradation. And generally errors in my case (a text editor) are rare, only disk IO, which is encapsulated in one VFS module, everything else, like non-closed brackets in code is expected behavior.

      The biggest differences were in third party libraries, UI, markdown parsing — completely different API and paradigms.

      > Performance characteristics of resulting rust

      I haven't measured. I don't think there's any significant difference between Go and Rust if app doesn't do allocations on a critical path. The reason I started this project was mainly to experiment (now I use similar approach to refactor much bigger legacy code base), and tree-sitter support is better Rust so it seemed like a good fit.

      • never_inline 18 hours ago ago

        Nice.

        It would help to clarify these things in the post. Your software is atypical of common Go software in the wild. The purpose of Go -> Rust rewrite would be usually the efficiency of rust.

        • aka-rider 16 hours ago ago

          I don't know. The most Go software I encountered is IO-bounded, and usualy it's network latency. Rust cannot meaningfully improve this.

          Although, in the agentic environment, a benefit of not having GC at all definitely helps.

  • vessenes a day ago ago

    The title is the worst part of the essay. Which is super interesting, to wit: fable's a very capable model when it comes to transforming concepts in and out of structural descriptions, and you can use it (along with a test suite I presume) to transpile a codebase. I wouldn't have thought to do this, but I think it makes sense, and I like it - it's using model intelligence at a few different steps for sensible things. Thanks for the writeup. De clickbait your title though or you'll keep getting clickbait rage responses :)

    • aka-rider a day ago ago

      I'm glad you liked it. I was trying to keep both, the title and the content as straightforward as possible.

      Another point is, Fable is reasonably cheap if you don't allow it to read or write.

      • vessenes a day ago ago

        Thank you. Yes I would like to hear more about that - I’d be interested to read details about limiting some of its native tool use.

        • aka-rider a day ago ago

          Fable is good at instruction following, so just adding the snippet I mentioned in the post is good enough for the most cases.

          There is a way to control tool invocations at the harness level when writing skills or agents.

          Example: ~/.claude/agents/critic.md

              ---
              name: critic
              description: >
                Plan Critic. Reviews an implementation plan. Use before the implementation.
              tools: Read, Agent
              ---
          
          For Claude skills, the frontmatter is different, the keys are:

              allowed-tools: Read Grep
              disallowed-tools: WebSearch Glob
          
          
          https://code.claude.com/docs/en/tools-reference
    • dilyevsky a day ago ago

      Ime it remains the best model for prototyping, sims, visualization etc throwaway scenarios. Just don’t look at the generated code if you just let it rip on the problem for hours ;) but that advice applies to any model unfortunately

      • aka-rider a day ago ago

        > if you just let it rip on the problem for hours

        In my experience, you can get good results if Fable does't write code itself, only spawn subagents.

        I can run Fable for 10 hours, and it would output 50k tokens and read 300k (30% of the context window). The resulting code is okay-ish. I would rarely merge LLM-produced code first try without an adversary review.

  • mikesolar0819 a day ago ago

    I recently rewrote a complex C++ program into Rust using the Strangler Mode, all codes are written by AI. Firstly, I split the code into some dynamic libraries, which uses C ABI to interacts with each other. Secondly, rewrite the libraries one by one. A init_xxx function are used to construct a object and a free_xxx is used to deconstruct it. A handle is used as 'this' pointer. In the caller side, write another class, constructor calls init_xxx and deconstructor calls free_xxx. No other code should be modified during the split.

    • aka-rider 21 hours ago ago

      Nice. Yeah, the general problem is how to divide and conquer. Your method is not always available (it depends on the language pair), in my case, Go packages didn't translate into Rust crates 1:1.

      • mikesolar0819 an hour ago ago

        Yes. Also it is hard for this method to deal with vtables. Two ways: writting a vtable yourself or write same inheritance in the caller side. Both is not good idea.

  • ramon156 a day ago ago

    what did i read? genuinely? its only a few words, and even that had to be AI written. The topic in the title barely was mentioned.

    • aka-rider a day ago ago

      Human-written. I was trying to be short and straight to the point.

      LLM-powered rewrites and huge refactors are better done using 1 additional step "convert the code to <something> that represents it best".

      The simplest example is, for a CRUD app it can be swagger description. The more complex behaviour exhibit the app, the more raw information should be provided.

      Like ontologies, "A is a child of B" model can derive and enforce that "B is a parent of A", and so on.

      On top of that, I write that Fable is reasonably cheap if one uses it solely for agent orchestration.

      • UltraSane a day ago ago

        I found this part to be interesting/clever:

        1. Extract the data representation

        Ask the LLM to represent your code as any combination of:

            graphs
            ontologies
            hierarchical state machines
            UML process charts
            constraints
            math formulae
        2 Operate on the representations

        3 Convert representations back to code

        • richstokes a day ago ago

          Do we think that was necessary? What would have happened if OP had just asked it to rewrite and test/validate each piece as it went until everything is verified and complete?

          My gut feeling is this is doing way too much, and it would've figured it out.

          • aka-rider a day ago ago

            But we know, Bun was 535496 lines for $165000.

            The whole point of this experiment was to try and make the rewrite as cheap as possible.

          • UltraSane a day ago ago

            converting code to more abstract and denser representations and then manipulating them makes sense to me. Finding better representations is like half of mathematics.

        • aka-rider a day ago ago

          this is the meat, yes.

      • brazukadev a day ago ago

        honestly it is hard to believe that seeing your replies and this heading: "The secret sauce".

        Giving the benefit of doubt, we all might be writing a bit like claude nowadays.

        If that is the case, I'd recommend reviewing the content before publishing to see if it sounds like a LLM.

        Or if you are trying to create "better" AI slop and think that is enough to say the text is human-written, don't do that, just say it was AI-generated or assisted.

        • aka-rider a day ago ago

          I wrote this elsewhere. Reading so much LLM output may have affected how I write.

          Probably I need some fresh air and a good fiction book.

          • abrookewood a day ago ago

            We'll all be writing this way before long ...

    • whateveracct a day ago ago

      pangram says 100% human

  • motbus3 a day ago ago

    Makes sense it would have been 6 USD in GLM 5.3?

    • aka-rider a day ago ago

      I doubt that it is possible with GLM.

      I haven't played with GLM 5.3, only with 5.2, so I cannot say for sure.

      GLM is at the level of Opus. Fable is something different entirely. It is capable of tracing the data flows of the app, I even tried it in a huge PHP codebase, it works.

      PHP is a weird beast because it allows something like

          $v = 'SomeClass' + 'Controller'
          ... // and later
          new($v)
      
      
      In other words, it could be hard to understand the code without running it, Fable reads this.

      And another distinct feature of Fable — it is an amazing orchestrator. I prohibit it basically read and write, and it operates a swarm of haiku and sonnet.

  • exabrial a day ago ago

    The best language a program to be written in is the original.

    Languages have conventions and best practices that aren’t portable.

    We could port COBOL to c and do a crap ton of goto/jmps and make a

         BEGIN MESS
    • aka-rider a day ago ago

      Of course language concepts don't translate.

      My point is that one can translate the data flow to another language.

      You could imagine any program as input -> [blackbox] -> output. For example, same pixels rendered on the screen provided identical keyboard input.

      I propose a way to decompose the blackbox.

  • cyanydeez a day ago ago

    And ROI of 0?

    • aka-rider a day ago ago

      Not at all. The example was an experiment.

      I did because I have a huge legacy code base, a distributed monolith, a few millions lines of code. Ideally, I want to get rid of it.

      At this point, I know a recipe to break the monolith, so I finally could eat the elephant piece by piece.

  • ykdhdjfzhg 19 hours ago ago

    Rkgff les plus distinguées cordialement

    Kfhmt

  • lhk931122 a day ago ago

    [dead]

  • yeasin-arafat a day ago ago

    [flagged]