• Translating a language into a different language is a popular thing to do these days, but still not a very easy one. I feel it's like peeling an infinite onion of misery. First, you write a parser of your source language, figure out the translation of the instructions, and emit the code in the target language, and you're very happy when your translated Hello world compiles.

    Then, a user (like me) tries writing something like

      package main
      
      func main() {
        register := 42
        println(register)
      }
    
    well, oops.

      /tmp/solod_build3904763637/main.c: In function 'main':
      /tmp/solod_build3904763637/main.c:6:21: error: expected identifier or '(' before '=' token
          6 |     so_int register = 42;
            |                     ^
      /tmp/solod_build3904763637/main.c:7:29: error: expected expression before 'register'
          7 |     so_println("%" PRIdINT, register);
            |                             ^~~~~~~~ (exit status 1)
    
    OK, now you grab the list of reserved words of the target language, which is not always an easy thing to do, and rename type names and variables as needed.

    The next bad thing is when you step on your own toes and see that the new names you invented, like `so_int` or `so_println`, will inevitably pollute the global namespace. We'll either cross our fingers and hope that no one will create a variable named `so_int`, or we'll need to add all our new kind-of-reserved words to our already big list of exceptions.

    I'm sure there are multiple levels of complexity beyond this.

    Not trying to say that seeing a bunch of new translators from language A to language B is bad: not at all! It really seems that this is one of the popular usages of the agents, and a rewarding one. But doing it without hidden bugs is kinda hard.

    • > The next bad thing is when you step on your own toes and see that the new names you invented, like `so_int` or `so_println`, will inevitably pollute the global namespace. We'll either cross our fingers and hope that no one will create a variable named `so_int`, or we'll need to add all our new kind-of-reserved words to our already big list of exceptions.

      To be fair, it's not like it's a completely foreign concept; consider C's categories of reserved identifiers (e.g., no double underscores or underscore followed by a capital letter) as well as the identifier ugilification that needs to be done in the C/C++ stdlibs to avoid collisions with user code.

      In that vein, the transpiler could pick some prefix which users are highly unlikely to use and document that said prefix is off limits (e.g., "You can't use identifiers starting with `_solod_id_`") or maybe it could use C's reserved IDs (idk if such a transpiler would count as an "implementation" as far as the C standard is concerned).

    • That seems like a brittle approach to transpilation. A transpiler should translate all of the language's semantics, including resolving identifiers as symbols, and then choose legal names for them in the target language. Also, there is so much more to a language than its surface syntax.

      I've never designed a transpiler (I'm not a programmer), but surely the correct approach is to transform the source code into its type-checked AST, and then translate to the target language from there?

      • > A transpiler should translate all of the language's semantics, including resolving identifiers as symbols, and then choose legal names for them in the target language.

        Yes, it should; but it also makes things much more difficult. This specific transpiler indeed builds an AST, but does not care about identifiers, just emitting them as is [1] (I hope I found the correct place in the code).

        [1]: https://github.com/solod-dev/solod/blob/8485bc867ae0f0269d75...

      • There is a lot of confusion around those words. I personally make a distinction between a "compiler" and a "transpiler".

        A compiler preserves the semantics - if you compile Scheme to C, you get a real Scheme program in C, with full semantics.

        A transpiler does not have to guarantee that. It is much easier to transpile Python to JavaScript than it is to truly compile Python to JavaScript. A transpiler can tolerate some amount of leakage between worlds (think 'arguments' as a variable name in Python vs JS).

        It really depends on your needs. Sometimes a transpiler is okay, sometimes totally inadequate.

      • I'm really sorry to be harsh but if you don't use programming languages and have never written a transpiler, why should anyone read your comment?

        You critique the approach as brittle and yet the approach you propose doesn't solve the thorny problem gp described of a growing ball of reserved keywords.

        • I've written multiple transpilers and their comment is how I do it. Safely mapping identifiers is one of those many edge cases you discover as you go along
        • They technically didn't say that they don't use programming languages, they said they're not a programmer. There's plenty of other people who use programming languages regularly, but not necessarily because they're into them.
        • You may have missed this in their comment:

          > resolving identifiers as symbols, and then choose legal names for them in the target language

          The responsibility for avoiding collision with the target language is in the transpiler; it should mangle identifiers appropriately to ensure you can't accidentally hit a keyword in the target language.

        • It's kind of hilarious isn't it?

          "I don't even write code, yet here is my technical assessment of how a tricky software problem should work".

          • > It's kind of hilarious isn't it?

            It is. I too find my competence profile a bit weird.

            I've been interested in security since I was 12 yet never worked full time as a software developer. I have done some coding, but that was over a decade ago, and even then it wasn't very much.

            On the other hand I understand the theoretical foundations of formal languages quite well, as well as the engineering required to implement them. I'm comfortable talking about any stage of the compiler pipeline, I can recite the Lambda cube and which logics the interesting corners correspond to, and I'm designing a family of programming languages in my free time.

            I understand digital design fairly well too for that matter.

          • Are you suggesting Ada Lovelace isn't capable of reasoning about a problem?

            You can come up with an algorithm or system without knowing programming. Presumably we can agree the opposite, that being a programmer doesn't give you mystical insight into every programming problem.

            Ultimately this isn't even a programming problem.

            Timmy writes homework, Jimmy writes homework. They can name the homework however they want. Both go in the same pigeon hole. How can the teacher tell who did which homework?

        • > I'm really sorry to be harsh but if you don't use programming languages and have never written a transpiler, why should anyone read your comment?

          Lots of reasons. If you can't come up with one then you're not the intended audience, and that's fine.

          I made the comment for several reasons. Here's two: (1) I had high confidence that my understanding is correct and wanted to share my knowledge with others. (2) In case my understanding wasn't correct I was hoping someone would correct me, resulting in both me and others learning some interesting nuance.

          As for why you in particular should read my comment: Curiosity. There are few traits that are as important to strategic thinking, creativity and success in reaching ones goals as curiosity. When I see something that doesn't map to my understanding of the world my reaction is to wonder whether I'm missing something. It has served me incredibly well so far.

    • Oof that's not a good look. You can trivially avoid this by just prefixing all variable names with a salt. By the way this (or a variant thereof) is called "avoiding unwanted name capture" if you want to sound all sophisticated :)
      • I think maybe the idea of all these transpilers is to keep the generated code readable and as close to the original code as possible. Mangling names into unreadable garbage is not difficult, but that would also make the the transpiler act more like an obfuscator, which is probably what the authors want to avoid.

        Protobuf has similar problem: whatever names you use for your proto messages should be translated to the target language as is, and with multiple target languages, chances are that you'll hit a keyword in one of them; each language plugin should figure out how to resolve this.

          $ cat test.proto
          syntax = "proto3";
          
          package test;
          
          message TestMessage {
            int32 register = 1;
            int32 foo = 2;
          }
          
          $ protoc --cpp_out=. test.proto
          
          $ grep 'register\|foo' test.pb.cc | head -n 2
                : register__{0},
                  foo_{0},
        
        (I may understand `register__`, but why `foo_`? no idea)
      • C++ compilers do this too, thats why so many to-be-linked symbols start with "Z"
        • Not only for the conflicts, but mostly to encode the parameter types into the name for method overloading, because the linker has no idea about it.
    • Add prefix 'noso_' to user variables.

      So even if someone creates 'so_int' it becomes 'noso_so_int'

    • A good test is to try to port significant from c++ to plain and simple C using "AI". Maybe it can retain some of the semantics for the original code.

      There is a more brutal option: AI could help write a c++ to plain and simple C transpiler... then we would lose the semantics of the original program, but free ourself from the very few toxic and real-life c++ compilers out there.

  • Go is a better C already, designed by C authors themselves, with other UNIX key figures.

    Which while some of the design decisions might be debatable, they actually knew what C is all about, informed by their own experience with what worked in C, Alef and Limbo, across UNIX, Plan 9 and Inferno.

    • > Go is a better C already

      It’s not. Garbage collection made sure of it. I believe everyone agrees that a "better C" has to have manual memory management. Most even rule out Go as a systems language because of GC.

      Of course, I’m pretty sure Go is much better than C at some problems. But there’s no way in hell it supersedes it.

      • Nope, only the anti-GC religion would agree to that.

        Most of those folks would never manage to replicate something like Xerox Cedar on their own, from 1980 in their beloved 2026 computers.

        Thankfully we have the likes of Apple and Google, that have a my way or the highway education system for such developers, that want to go through their magical gardens.

        • There are roughly two orders of magnitude more microcontrollers in the world running code than application processors. GC is not acceptable on a microcontroller due to the extreme resource constraints. The GP post is correct, Go can replace some use cases for C, but it does not replace all use cases and GC is part of the reason.
          • Go already runs on microcontrollers, but _just like C_, care must be taken to avoid using features that are not compatible with microcontrollers (such as dynamic memory).
        • Most of those folks would never manage to replicate something like Xerox Cedar on their own, from 1980 in their beloved 2026 computers.

          What are you talking about

      • > I believe everyone agrees that a "better C" has to have manual memory management.

        This seems completely wrong. Manual memory management is perhaps C's most famous issue. I'm sure _someone_ thinks manual memory management is a feature rather than a bug, but I don't think there's any broad consensus about this at all.

        Moreover, Go gives you a lot of levers to control your allocations, and with some care (probably less care than writing correct C code) you can avoid allocating at all (this is how Go's own runtime works).

      • > Of course, I’m pretty sure Go is much better than C at some problems. But there’s no way in hell it supersedes it.

        C is great when you need to do manual memory management. Most software written today doesn't need to do manual memory management. (And frankly, for the typical software project, manual memory management is a liability.)

        • > C is great when you need to do manual memory management.

          Is it still, today? There are other manual memory languages today with better safety records and ergonomics. Plus a host of new and better features.

          I think C is really great if you need C. For libraries, for knowledge, for size, for compatibility, for "simplicity", for fun, for whatever.

          But other than having a strong reason to want C, on a purely language feature comparison, it's not great.

    • Yeah but they were intentionally trying to build a better C++/Java, not a better C. It wasn't even aimed at things that C is good at. It was mostly aimed at writing high performance servers that have to scale really big not only in terms of performance but software complexity, size and contributions. So Go is a better C++ or Java for writing servers according to its creators.
      • A better C++ is by definition a better C, no one should be using C in 21st century beyond UNIX clones, and embedded devs that are religiously against C++, even all modern C compilers are written in C++ nowadays.

        Anything you can think C is better, it isn't ISO C, rather non standard C compiler specific extensions, which can language can also be.

        Just do like in K&R C days, use Assembly for what language isn't directly capable of, and it is right there as part of a regular Go toolchain installation.

        • > A better C++ is by definition a better C

          The definition is wrong, then.

          I wrote C++ for most of my career. And as of late, I found myself avoiding more and more features from it. The STL is mostly trash, not worth the increase in compilation times. Templates are good for containers, but that’s about it. Inheritance and polymorphism are circumstantial enough that I’m not sure they’re worth adding to the language: in the rare cases I do need them, I can always write my v-table by hand.

          The more I write C++, the more I find C is not that far from that "much smaller and cleaner language struggling to get out". And I say that fully aware of the many egregious faults still present in C.

          There are two features from C++ I would really miss in a big C project: generics (templates), and destructors. But then we can always write a lightweight pre-processor to add those generics and a `defer` statement. Even if it requires a full parser, C parsers are pretty easy to write.

          • I've been toying with a better C... https://github.com/panaflexx/classyc

            Started with the excellent MIR compiler, and I wrote much of the class/string/json/dict, exceptions and AI made the generics,ownership tracking, and safety checks/traps. Added some go

            The memory model is mixed, I ended up using arenas for dictionaries and adding a full ownership checking / safety checking compiler stage.

            It's purely for the joy of making something interesting.

          • I see it differently, given how C with Classes came to be, a Typescript for C in 1989.
            • The origin of a thing does not forever define what that thing is and always will be. C++ has evolved far beyond C with Classes.
      • > Yeah but they were so that intentionally trying to build a better C++/Java

        They were trying to build a faster Python, thinking that would appeal to C++ developers. The theory was that developers were using C++ at Google because they had to, not because they wanted to, and would choose something like Python instead if it were up to the performance task. Although it turned out in the end that C++ developers actually wanted to use C++.

        • No they weren't, in fact they were very surprised by the adoption from Python folks.

          "I was asked a few weeks ago, "What was the biggest surprise you encountered rolling out Go?" I knew the answer instantly: Although we expected C++ programmers to see Go as an alternative, instead most Go programmers come from languages like Python and Ruby. Very few come from C++.

          We—Ken, Robert and myself—were C++ programmers when we designed a new language to solve the problems that we thought needed to be solved for the kind of software we wrote. It seems almost paradoxical that other C++ programmers don't seem to care."

          https://commandcenter.blogspot.com/2012/06/less-is-exponenti...

          • > No they weren't, in fact they were very surprised by the adoption from Python folks

            I'm kind of surprised that the Go creators were surprised by this.

            Like I know they didn't like C++, but Go is by no means a replacement for C++ despite whatever was said about "building a better C++/Java".

            It took so long to pick up generics that Rust was already around and the logical next step for C++ developers by the time that happened. And that's only scratching the surface of why people choose C++.

            On the other hand, having a more performant "simple" language that directly supports concurrency and lets you compile to native code without a ton of ceremony could be very helpful indeed if you're a Python dev who need to take an app to the next level without having to learn intricacies of C FFI or the GIL.

            • Why wouldn't they be surprised? Python users were already using Python, so presumably it already solved their problems and they wouldn't benefit from another Python. Through Google's eyes, anyone who needed performance would have already long abandoned Python for C++.

              What Googlers don't have a grasp of is how resource constrained most other businesses are. They cannot afford to hire C++ experts and were using Python because Python developers were the only developers they could get their hands on, even where Python wasn't providing sufficient performance.

          • > No they weren't

            Indeed they were. Your quote even says so — seeking out to solve the problems C++ was thought to have, which is that it didn't have the ergonomics of languages like Python, as explained in the original public Go announcement. To "feel like a dynamically-typed language" was a primary motivation. That was clearly told.

            You can certainly hold the view that a better C++ and a fast Python are one and the same, but I suspect the HN crowd will vehemently disagree with you. Conflating the two would not serve to communicate much here.

            > were very surprised by the adoption from Python folks.

            Quite naturally. Python users were already using Python. One would be inclined to think that they didn't need another Python. Except it turns out they did, because it was actually they who needed a faster Python.

        • > Although it turned out in the end that C++ developers actually wanted to use C++.

          Oof, I don't think so. It's just ridiculous how many things Google uses C++ for where something like Go or Java would be a better fit, and everyone I talked to agreed. No one liked C++ for search-like things.

          I think they just underestimated how powerful the network effects were. People wanted to use Go, but then it didn't have Flume support forever, so what can you actually do with it? And all the NLP libraries were in C++. And the vector-search library was C++, and graph clustering, and so on. One of the basic data formats was super-clunky for ages as well, but I forget if it was SSTable / RecordIO / Capacitor or what.

          Or perhaps the Go creators were just writing very different code in very different domains from what I saw as the bread-and-butter C++/flume data-crunching pipelines of Search and Maps.

        • > Although it turned out in the end that C++ developers actually wanted to use C++.

          Survivorship bias. You're only looking at the people who remained C++ developers. A bit like a politician bragging that they have 100% approval rating among their supporters even as their supporter count dwindles.

          • Google kept on building C++ services despite Go being available and fully backed by the company. Developers could have used Go if they wanted to, but they didn't.

            There are obviously exceptions. There always are. But the reality is that Go was picked up by the Python crowd instead. Which was noted as being surprising at the time as it was assumed that Python users didn't need another Python. What was hard for the Googlers to fathom was that anyone would use Python in a performance-sensitive area to begin with.

    • Go is not a better C, in the sense that you cannot write an OS with it. Runtime, GC, etc.

      But Go is a better language for many programs that were often written in C: network servers, CLI utilities, TUI utilities, etc.

      • Plenty of OSes, since Xerox PARC days have been written in GC systems languages.

        Interlisp-D, Smalltalk, Cedar, Topaz, Oberon, Active Oberon, Singularity, Midori, Ironclad

        Go's runtime is written in Go.

        The whole compiler toolchain, GC, compiler, linker, Assembler, is written in Go.

        There are Go compilers for bare metal, no OS needed, like TinyGo, the runtime, written in Go is the OS.

        I love the "you cannot write an OS in a GC language" discourse.

        It isn't only a mainstream thing because everyone only cares about UNIX clones.

        • The fact that people care a lot about Unix clones is significant, though. nine_k could have been more effective in arguing the point, but it seems like a strong point to argue. Do you think you Go is flexible enough to write a Unix clone with performance equivalent to a C-unix? If so, why has it not been done?
          • Besides the sibling Biscuit, maybe because no one bothered to do it?

            As simple as that, not everyone of us is a Linus.

            I should also point out that if you are using a Mac, changes are its iBoot Safe C might already been replaced by Embedded Swift, a GC enabled systems language.

            Chapter 5 of The Garbage Collection Handbook, or A Unified Theory of Garbage Collection paper for the incoming replies related to RC.

            People care about UNIX clones because they are lazy, UNIX has the source code available, and an existing ecosystem that they don't want to replicate, so it always ends up being yet another clone, thus throwing away all the possible innovations.

            We see this happening even with Haiku, Genode, Redox OS, or Windows now shipping alongside Linux on top of Hyper-V.

            Unless one is an Apple or Google, with the money and will power to push something out the door, using Objective-C, Swift, Java, Kotlin, with plain C and C++ standard libraries, and even then people will bend backwards to put UNIX into those systems, even when the platform owners went to great effort to hide it under the official userspace APIs.

            • > As simple as that, not everyone of us is a Linus.

              I’m pretty sure Linus could not have written Linux today. Too much hardware to support, too many drivers to write, before it’s remotely useful. Well, except perhaps on some specialised servers.

              Yes, not everyone is Linus. Otherwise we’d be using GNU Hurd. But he also came at the right time.

              • It is no accident that recent attempts to write hobby OSes nowadays target type 1 hypervisors instead of real hardware.
            • > People care about UNIX clones because they are lazy, UNIX has the source code available, and an existing ecosystem that they don't want to replicate, so it always ends up being yet another clone, thus throwing away all the possible innovations.

              Which is a real shame, because people thinking outside the UNIX clone box have come up with some incredibly innovative operating systems like Plan 9 and OS/400.

          • > If so, why has it not been done?

            Because of the 30 million lines problem. Writing a serious OS kernel nowadays is flat out impossible: the hardware is just too diverse, it requires too many drivers. The best we can do right now is just add to an existing kernel. Kind of a vicious cycle: the more drivers we accrete to any given OS, the more impossible it is to get feature parity from the ground up.

            The only solution to that is for hardware vendor to standardise their interfaces (at the hardware level), and actually give us the fucking manual. And I mean the real manual, the one that tells us voltages and pins and baud rates and the actual wire formats required to talk to it. A proprietary Windows driver is not a manual, even if it comes with an SDK. Heck I’m not even sure the source code of a Linux driver would count.

            But they won’t do it. They just won’t. So unless we do something drastic like forbidding hardware vendor to ever ship software (to force them to standardise and document their actual interfaces), writing another OS that can actually compete with the existing ones will remain flat out impossible.

        • > Go's runtime is written in Go. The whole compiler toolchain, GC, compiler, linker, Assembler, is written in Go.

          There's some nuance to this. The runtime code uses specific compiler support and restrictions that are not ordinary Go - possible (or even done, like this case) ≠ ergonomic. No doubt of course that for the Go project, this is still a win.

          • Do you think libc is also written in pure ISO C?

            I love how language extensions, and subsets are always valid for C and C++, but used as an attack against other languages, as if to prove they are not good enough for a specific use case.

            Well, neither are C and C++, as they either have to rely on hand written Assembly code, language extensions, or be gutted down into subsets outside the official language standard.

      • > Go is not a better C, in the sense that you cannot write an OS with it

        Can you even write an OS in pure ISO standard C? I know atomic (https://en.cppreference.com/c/language/atomic) was added in C11, but is that sufficient to write an OS? How do you write a kernel-user space transition in standard C, for example?

      • The larger runtime makes bootstrapping go for unsupported architectures more laborious than C, but it's not a hard blocker. The function call overhead for inline assembly feels like more of an issue doing close to hw programming. It can be avoided for the runtime, but user go code can't escape it afaik.
        • Just like when C was being brought to life in PDP hardware and there was nothing else, someone has to put the work into it.
    • I disagree. Go's main plus point is concurrency, whereas the irony is it lacks thread safety—something languages such as Java have had from, let's say, day one. You can fix that issue by manually managing sync.Pool objects for performance and, on top of that, use channels, but this completely defeats the purpose of Go's simplicity. Even if you want a top-of-the-line performance with some convenience, there exists an open-source framework called Netty. It is an absolute beast for network I/O, beating out Rust in some cases and sitting just behind C. And it's all in Java.
      • My point was not about Go vs Java.
        • You missed a bit of my point. The point am trying to convey is that what it was made for that is efficiency and networking it fails somehow and somewhere in both. As i was surprised when i came across the thread safety issue of go which for me was diabolical, because go was meant to be lean at least on threads while maintaining thread safety by default.

          The next point would be gc,maybe it can be improved and its being improved the recent being mark sweep algorithm was made a bit efficient by addition of more meta data about the total object structure, not going into it more.

          Thing is it breaks the fundamental promise it was suppose to keep and yes its better than rust for network applications(am talking of getting things done in default way). It's stdlib is the strongest among all languages.

          That summarises my point go needs severely improve it's issue of thread safety by default provision and gc efficiency.

    • Wikipedia says Alef lacked garbage collection, contributing to it being abandoned.

      But does Limbo have any 'fatal flaws' like that? Especially compared to Go.

      No doubt Rob Pike is a prolific and capable programmer. But seems like he needed quite a few attempts before arriving at Go (looking at C's flaws -> Alef -> Limbo -> Go, Wikipedia also mentions a domain-specific language called Sawzall).

      • Which is another proof, that the professional experience of the UNIX idols, has shaped why Go, and not C all the way.
    • ZIG is already the better C.
      • Zig is what Modula-2 already offered in 1978, Ada in 1983, Object Pascal in 1986, revamped in curly bracket syntax.

        We need a little more in 2026, besides compile time execution.

        • Aside from a GC, what other features are "more 2026"? I'm curious.
      • I really wish it had more industry buy-in, in terms of funding and community participation. The language has so much to love about it, and even the typical criticisms - some deserved, some not - can be improved or solved over time because it has solid design and foundation. Like most well-built systems, there's a single person (or few people) with coherent vision driving the development, in contrast to C++ and other "design by committee" style projects.
  • The idea of using a subset of an existing popular language is very wise IMHO. We can (and apparently are) debating the merits of the language runtime, but what a subset gives you is immediate access to a large pile of existing tooling that you'd have to write yourself, eg linters, formatters, lsps, etc. Stuff that is purely source-oriented.

    That hadn't really occurred to me before.

    • That seems like a smart insight... but, if you're going to use an existing linter it will lint the full existing language and not your subset.

      So, if you accidentally code something that is not in the subset but is in the full language, the linter would then happily accept that. Imo there will be similar issues for lsps and formatters also. You're going to probably end up in a situation where you have to fork all of those anyway.

  • The author's original blog post, which goes into some more detail: https://antonz.org/solod
  • The problem with these type of new / transcompile languages is not the langue, its the lacking libraries and 3th party assets. Great if just want the most basic hello world programs, but the moment you need ... for example a http server. Then your often with:

    a) none

    b) http 1.1

    c) ... forget about more

    Maybe you need rar support ... O well, ... And then you always enter the world where you need to start linking external libs, and then your mixing not just the base language and the transcompile but also whatever interface for calling those external libs.

    Ironically, with LLMs being around, your often better to just have it write whatever is missing. Until you find out then, that the language misses some feature.

    O great, you needed crypto support. Ok let the LLM write it for you, its only 100x slower then whatever was written years ago and had tons of enhancements and edge cases fixed.

    At that point, you can just tell a LLM to write in C from the start, and be done with it. lol.

    Transcompile languages have always had tons of issues, and there is a reason why non became popular. Haxe comes to mind. How many years this exist and barely anybody knows it. Because your often just better writing in the original language and fixing the issues, or picking a better fitting language for your project.

    • > Transcompile languages have always had tons of issues, and there is a reason why non became popular.

      While implementations have all died out now in favour of direct compilation, C++ the language was designed to be a transpiled language, and was for many years with C as the target. You can likely find many who agree that it has tons of issues, but unpopular it is not.

      • Typescript is an even better example. And there are some domain-specific languages that aren't meant to become popular general-purpose languages, but succeed in their niche through the help of transpilation to a general-purpose language.
        • Typescript isn't nearly as popular as C++ and, aside from a couple of legacy features that don't seem to be commonly used, it can be erased without needing transpilation. What makes it a better example?
  • bb88
    How does it deal with pointers if everything is stack based? You can't really return a pointer to something on the stack because it could get overwritten between when you return it and when you access it.
    • wrs
      Exactly as well as C does, it seems.

          func newPerson() *Person {
              p := Person{Name: "Alice", Age: 30}
              return &p
          }
      
      becomes

          static main_Person* newPerson(void) {
              main_Person p = (main_Person){.Name = so_str("Alice"), .Age = 30};
              return &p;
          }
      
      Quoting the FAQ: "So itself has few safeguards other than the default Go type checking. It will panic on out-of-bounds array access, but it won't stop you from returning a dangling pointer or forgetting to free allocated memory. Most memory-related problems can be caught with AddressSanitizer in modern compilers, so I recommend enabling it during development by adding -fsanitize=address to your CFLAGS."

      So saying you get the "safety of Go" is a bit of a stretch.

      • Yeah that's not great. It's easy to be faster than go if you haven't thought about memory management yet. I bet go with GOGC=off is faster than plain go too.
        • This is impossible. General words like "faster" are subjective, and useless in a technical context unless you ground the discussion by giving them specific definitions. Otherwise everyone ends up talking past each other.
      • That's undefined behavior in C I thought? You're addressing the memory of a stack frame that already collapsed when it returned. I think it's ok for compilers to either segfault or work like you'd think they would for that example in C.

        You can pass pointers to earlier frames in the stack, they're still active, but you can't return a pointer to an expired stack frame.

        • I think you're basically agreeing with the person you're replying to; they're pointing out that Solod doesn't really provide the "safety of Go" since the translation trivially exposes the user to UB that would not be present in Go.
          • You're right, I misread their point, sorry for the pedantry OP.
    • Well, it does say:

      "Everything is stack-allocated by default; heap is opt-in through the standard library."

      So it supports both stack and heap, and I guess static allocation too.

  • > So is for Go developers who want systems-level control without learning a new language. And for C programmers who like Go's safety, structure, and tooling.

    Wut?

    Also, how do you preserve garbage collector semantics without garbage collector?

    • The answer is apparently "you don't":

      - Everything in the language is statically allocated or stack-allocated. You have to call a malloc / free function to get heap allocated things

      - The language is not memory safe (you can't return slices, pointers, or interface types from a function if the thing was created inside the function, unless you used heap allocation)

      - Interfaces (the only variable size struct Go has) are implemented by creating a struct of function pointers. Arrays and maps (the non-struct variable size types) are implemented as stack-only and maps are limited to 1024 keys. You can opt into heap-based arrays / maps in the standard library to bypass this.

      • It sounds incredibly dangerous in the hands of a usual go programmer who has no idea what the difference between the stack and the heap is.
        • Been a while since I used go but I remember it being kind of uniquely hard to tell? Like a struct is on the stack, but a *struct is maybe on the heap, depending on escape analysis?
          • In go you don’t need to care, the GC will take care of allocations on the heap and the runtime will choose when something should go on the stack. That’s the problem: in this other language it’s suicidal to program as if it was the same as Go as you will just make huge mistakes like returning a pointer to a local variable.
          • isn't it the exact same as C in this regard? The pointer being on the stack or not depends how it was originally allocated.
            • In C you explicitly malloc things onto the heap. In go, taking the address of something maybe allocates on the heap, or maybe not if escape analysis can keep it on the stack.
      • So much for "Go's safety" in the quote above. Ok, it doesn't explicitly say memory safety, but what other safety could if be referring to?
        • it could also be Typesafe at compile time
        • comparing it with c? thread safety maybe?
          • As far as I understand co-routines help don't really help with memory shared across go-routines. They only help in the fact you need to manage spawning and joining threads, making it easier to do stuff in parallel. But they don't provide thread-safety.

            edit: I suppose you don't get segfaults or buffer overflows and the sort in go for accessing memory in a parallel context, you get recoverable panics. But that is still not really thread safety in my opinion, it is memory safety.

  • The "a better C" meme needs to die. It's ill defined. Everyone wants something different. For me, GC disqualifies any language as a better C. Bjarne Stroustrup promoted C++ as a better C. But C++ killed off some of C's killer low-level features like type-punning via unions. Indeed it's only in recent years that low-level memory manipulation, such as std::start_lifetime_as and the implicit lifetime rules were standardised. The whole strict aliasing fiasco made C and C++ permenantly worse. Some people say Zig is a better C, but it is certainly not a minimal language, if that's how you define better. For me a better C would have an abstract model that matched machine-level memory access (i.e. no type-based alias analysis) would be as minimal as C in terms of feature set, would clean up C warts like operator precedence, and would be as deterministic as possible (e.g. deterministic memory layout, including bit fields, would be possible without hacks)...
    • Everyone agrees C has problems, but there’s no consensus on what those problems are. People build ‘better Cs’ to solve the problems they see in the language, and offer them to the community for the benefit of those who share their tastes.

      It’s perfectly fine for you to disagree with them, but it’s also perfectly fine for them to publish their solutions to their problems.

      ‘A better C’ is a good description for these projects. ‘The better C’ would not be.

    • John Regehr tried to start an initiative to make what he called Friendly C, removing some of the most blatant C footguns, and even that turned out to be extremely hard to get consensus on: https://blog.regehr.org/archives/1287
    • What do you think of Ada's representation clauses and Zig's packed structs? Do they give you the syntax and semantics for arrangement (ordering, padding, widths), endianness, and control of bit order that you want?

      Also, thank you for an educational comment.

      Edit: I forgot to ask about your thoughts on Ada's and Zig's type punning.

    • It also varies heavily on the kind of static analysis tools you are using in conjunction with your compiler. Some "bad" things about the language are just fine if they can be caught by the static analysis you are using.

      It is a major problem with most really old languages, JS is notoriously prone to this kind of "remove the bad bits" thinking when in actuality most of those complaints are non-issues if you run a linter.

    • [dead]
  • Does it generate the same extremely fat binaries? I've seen Go binaries get into hundreds of megabytes for things you could do with C/C++ with a few megabytes. Most of it seemed to be string tables and other things that could be reduced but not eliminated with compression.
    • A large part of that depends if we get something equivalent to gc's scheduler or not. Concurrency is still under development. Most likely it will take a simpler approach, like tinygo, which won't require tons and tons of code.
  • I know this is probably a bad question but it says that this language would be good for C developers who like Go's safety. Isn't Go's safety achieved by its garbage collection, which is eliminated in this language? What elements of Go are safer than C which would be preserved in this subset language?
  • Very interesting. I have a personal experimental project to convert go to c++ but it's less advanced than this (https://github.com/Rokhan/gocpp). My initial intention was to manage garbage collector with some smart pointer or something like Boehm GC but I've still not reached the point where it's the main problem to solve.
  • I really like this idea. I was reading a post earlier about how Go generics are implemented, and how they're sort of leveraging root GC-types in the "runtime" to avoid the same bloat as monomorphization causes in, say, C++. I wonder how Solod will do that? I guess plain monomorphization? I guess that's fine since C compilers are so speedy.
  • I've been using Go and Raylib to make a game lately and I really don't have a problem with garbage collection. It's so fast that it's not having an impact on my frame rate.

    I was a little worried at the start because nobody would normally consider Go for games, but I did a bunch of tests and found it's just no big deal.

    (I'm focused on game play and not interested in pushing hardware to its limits.)

    • I’ve been considering using Odin and Raylib for this because of its similarities to Go, but using Go itself is appealing. Do you have any good resources for what you’ve learned, or is it an unexplored frontier?
      • I’ve used Odin and Raylib for some prototypes, and it’s terrific!
      • I don't know If I can be very helpful, I'm using gen2brain's binding [1].

        I started about a year ago asking the AI very beginner questions about Go and 3d math. I think it did steer me down some wrong path sometimes and of course I did some dumb things myself too. I'm not using Agents, just asking questions about features, then writing the code myself by hand.

        I really like the power of the tools and the constraints of the language in Go. It's been fun so far.

        [1] https://github.com/gen2brain/raylib-go

        It's interesting you would mention Odin because I spend a fair amount of time playing with it as well. It was easy to get started and fun. Fast, easy to iterate. The reason I moved away was not the language itself, but I felt it was too much Ginger Bills baby. Oh, and managing memory is no fun. I want to make game play, not think about allocations :)

  • I doubt that it can. so in addition to C's quirks (which I know about), I have to care about go's quirks and solod's quirks as well? and for what? there's no solod-to-regular-go interop aiui, so just some tooling and the standard library?
  • At first glance looks like stipped C++ with minor differences. For example go have row polimorphism compared to OOP in C++. What else is there that C++ does not have?
  • It cannot be a better C. You cannot implement exceptions in it using set jump for example, but the biggest problem is memory management. You can't implement your own arena allocator in golang.
    • I've drastically sped up commercial shipping C code by implementing arena allocators and Go is my daily driver and it's not clear to me why you're making this claim.
      • Not the OP but I guess what they are saying is that since this language is a subset of go and if you use it as such then an arena allocator cannot be used in the transliterated code.

        Maybe it's possible to force the transliteration to use a different allocator and then you could use the one you wrote in C?

    • To be fair, you don't need to implement exceptions in golang because they already exist in the language, they're just called panics
      • Indeed, but I guess OP is saying that the panics are not supported in this language.
  • i've been using Go on backend now all the time.

    Wish something like this existed instead i am stuck with flutter and react native on Mobile.

    When will a time come when i can use some functional languages like Haskell or a plain boring language like Go for making apps with OTA ability for mobiles.

    As vibe coding takes over, app store approval will become slowerer and OTA is really great when you need to make quick changes!

    You can OTA each day and do base app release to store once each week.

    i think this maybe the space where very little work is being done.

  • I did this with a python languah
  • Insert Look What They Need To Mimic A Fraction Of Our Power meme here.
  • Arn't goroutines the killer feature of go? Don't see how you'd get them with this approach.
  • Does it support pointer arithmetic?
  • This looks silly. It's about a Go subset with no GC and various other restrictions that make it map onto C. But then you have most of the problems of C. It's unclear what the advantages are supposed to be. Rust or Ada seem way preferable, depending on the application area.
  • bun tried hard to be written in zig.

    eventually, they fell back to rust.

    there's a lesson here: subset languages are fine for experiments and small projects, but they're rarely the right choice for production software.

    ...and C still can't be replaced. it's still the language of choice for mission-critical systems and low-level problem solving.

    • Good point! Regarding C being the language of choice for mission-critical systems, probably you want to avoid memory bugs that might result ruining the mission. I understand many projects have large C codebases or interact with other projects in C, but migrating to Rust when possible (like replacing lead pipes as you find them for plastic pipes) sounds like a smart choice to build mission-critical low level systems.
    • If with "production software" you mean large pieces of software I'd generally agree.

      I personally like Zig but I'd never write a huge 200k loc project with it, I see it more fit for low level stuff like small embedded devices where you must interface with C code.

    • What's the lesson to be learned from Roc migrating from Rust to Zig?
    • [dead]
  • This is a very exciting project; love writing go with the tooling, but I miss writing C from my getting started days
  • NO Developers who use a particular language reshape their mental model to fit that language. Go is centered around its runtime. If you switch to C11, do you really need to be thinking about a goroutine scheduler, never mind garbage collection? Even just looking at example code, would a Go developer ever think defer pool.free is necessary? The mental model is completely different.
  • no it cant.
  • Yet another attempt to reinvent a better C. Curious, but unpractical. If one need a better C, C++ should be used instead.
    • C++ is like PHP: it used to be a terrible language, and you can still reach for everything terrible if you wish. But during last maybe 10 years, C++ made a lot of effort to become a language with fewer footguns and more safe, high-level tools.

      Still I won't start a new project in C++. If I wanted high-level features and zero-cost abstractions, I'd take Rust. If I wanted working really close to hardware, do bit-twiddling and knowing where every byte is allocated, I'd take Zig. If I wanted to write a small piece of code intended to run absolutely everywhere, including old and esoteric architectures, I would still have to go with C (plain, old).

      • > If I wanted working really close to hardware, do bit-twiddling and knowing where every byte is allocated, I'd take Zig

        Why not C++? It allows as many low-level operations as one wishes, but don't forces you to manage memory manually where it isn't necessary.

        > If I wanted to write a small piece of code intended to run absolutely everywhere

        GCC and Clang have support of C++ since many years. Is there any modern platform for which no GCC or Clang backend exist?

    • > Yet another attempt to reinvent a better C. Curious, but unpractical. If one need a better C, C++ should be used instead.

      Those two languages are on the opposite ends of any complexity scale. Someone looking for a better C has a ton of options before getting to "lets use C++ and ask our devs to practice discipline".

  • [flagged]
  • It cannot. C is a wonderful language that makes me smile every time I pick it up. A truly universal tool that lets you go wherever your heart desires. Go is a prison designed to enforce a bleak uniformity on all of it's users. For only by painting everything a uniform gray can we ensure we are all equal.
  • Go is not like C in any way. It doesn't feel like C, it feels like C# with mediocre syntax changes and extremely explicit error handling -- like someone took the bad parts of C and added them to a high level language.

    I don't get it at all. Green threads are cool, but again, it's easy to write unsafe concurrent code in Go, so why would I choose it over e.g. Rust (where its hard to write unsafe concurrent code) or C++ (which gives me more control)?