5 ms·
Zen-C: Write like a high-level language, run like C
- ethin 9mo agoAm I the only one who saw this syntax and immediately though "Man, this looks almost identical to Rust with a few slight variations"?
- CupricTea 9mo agoIt seems to just be Rust for people who are allergic to using Rust. It looks like a fun project, but I'm not sure what this adds to the point where people would actually use it over C or just going to Rust.
- nnevatie 9mo ago> what this adds I guess the point is what is subtracts, instead - answer being the borrow-checker.
- Ygg2 9mo agoSo it re-adds manual lifetime checking. Got it.
- askyng 9mo agoIt might or might not be a toy project, I'm not sure, but one advantage of subtracting the borrow checking is that the compiler avoids a lot of complex machinery. Borrow checking in Rust isn't sound AFAIK, even after all these years, so some of the problems with designing and implementing lifetimes, region checking, and borrow checking algorithms, aren't trivial.
- Ygg2 9mo ago> Borrow checking in Rust isn't sound AFAIK, even after all these years Huh? If borrow checking in Rust is unsound, that's akin to saying Rust is utterly broken. Sounds like you've been fed FUD. If Rust was that unsound, Rust haters would flood Twitter with Rust L takes.
- imtringued 9mo agoNot just that, it would also mean that every single Rust application is riddled with very noticeable miscompilation bugs due to the fact that Rust makes heavy use of strict aliasing rules for optimization. This isn't something that can easily be sweeped under the rug without people noticing.
- Ygg2 9mo agoI'm reading it as charitably as possible as in "Maybe some lifetime in some arcane combination is unsound." I did heard that 'static lifetime shouldn't be permitted in some cases. The premise is too ridiculous to engage seriously. Apparently Google/AWS/MSFT/C++ engineers all missed a huge gaping hole in Rust borrow checker, something that random commenter could pick up.
- petcat 9mo ago> answer being the borrow-checker There is an entire world in Rust where you never have to touch the borrow-checker or lifetimes at all. You can just clone or move everything, or put everything in an Arc (which is what most other languages are doing anyway). It's very easy to not fight the compiler if you don't want to. Maybe the real fix for Rust (for people that don't want to care), is just a compiler mode where everything is Arc-by-default?
- the__alchemist 9mo agoMaybe take the parts of rust the author likes, but still encourages pointers in high level operations?
- suioir 9mo agoI thought the same and felt it looked really out of place to have I8 and F32 instead of i8 and f32 when so much else looks just like Rust. Especially when the rest of the types are all lower case.
- unwind 9mo agoAgreed, that really stood out as a ... questionable design decision, and felt extremely un-ergonomic which seems to go against the stated goals of the language.
- hyperhello 9mo agoEvery language is apparently required to make one specific version of these totally arbitrary choices, like whether to call the keyword function, func, fun, fn, or def. Once they do, it’s a foolish inconsistency with everything else. What if the language supported every syntax?
- deleted 9mo ago[deleted]
- turbotim 9mo agoMy immediate thought was it looked a lot like Swift
- deleted 9mo ago[deleted]
- Gys 9mo agoInitial commit was 24h ago, 363 stars, 20 forks already. Man, this goes fast.
- worldsavior 9mo agoCould be bots.
- deleted 9mo ago[deleted]
- directmusic 9mo agoDefinitely could be, but the dev has been posting updates on Twitter for a while now. It could be just some amount of hype they have built.
- alexpadula 9mo agoIt’s not, it’s just how hackernews works. You’ll see new projects hit 1k-10k stars in a matter of a day. You can have the best project, best article to you but if everyone else doesn’t think so it’ll always be at the bottom. Some luck involved too. Bots upvoting a post not organically I doubt is gonna live long on first page.
- worldsavior 9mo agoThe stars are on GitHub, they can come from somewhere else, e.g. the author himself buying stars.
- alexpadula 9mo agoThis is hella common. Companies have too much money to spend.
- Duendek86 9mo agoHi, I'm the developer's father. Trust me, he hasn't bought a single star in his life—not even in Super Mario :p
- deleted 9mo ago[deleted]
- giancarlostoro 9mo agoSyntax aside, how does this compare to Nim? Nim does similar, I think Crystal does as well? Not entirely sure about Crystal tbh. I guess Nim and Vala, since I believe both transpile to C, so you really get "like C" output from both.
- jdc0589 9mo agoman I haven't heard anything about Vala in ages. is it still actively developed/used? how is it?
- spookie 9mo agoYes, it is actively being developed. Quite easy to make apps with it and GNOME Builder makes it really easy to package it for distribution (creates a proper flatpak environment, no need to make all the boilerplate). It's quite nice to work with, and make stuff happen. Gtk docs and awful deprecation culture (deprecate functions without any real alternative) are still a PITA though.
- deaddodo 9mo agoVala is still being developed and used in the GNOME ecosystem. Boo, on the other hand, is pretty dead.
- giancarlostoro 9mo agoThere's a surprising number of GUI apps built using Vala, if you've used Linux long enough, there's a chance you may have used a Vala based GUI and not even known you were. It's just such a nice language, it's a shame it's not more prevalent since Gnome libraries can compile basically anywhere.
- GrowingSideways 9mo agoWhy not compile to rust or assembly? C seems like an odd choice. In fact why not simply write rust to begin with?
- ndr 9mo agoAt times people think C is better. See recent discussion about https://sqlite.org/whyc.html https://sqlite.org/whyc.html
- alexpadula 9mo agoC is best
- xnacly 9mo agoAssembly requires way more work than compiling to, say C. Clang and gcc do a lot of the heavy lifting regarding optimisation, spilling values to the stack, etc
- GrowingSideways 9mo agoThen you're stuck with the C stack, though, and no way to collect garbage.
- saidnooneever 9mo agoreally? you cant track and count your pointers in C? why not?
- UncleEntity 9mo agoI have a couple interpreters I've been poking at and one uses 'musttail' while the other uses a trampoline to get around blowing up the C stack when dispatching the operators. As for the GC, the trampoline VM has a full-blown one (with bells-and-whistles like an arena for short lived intermediate results which get pushed/popped by the compiled instructions) while the other (a peg parser VM) just uses an arena as the 'evaluation' is short lived and the output is the only thing really needing tracking so uses reference counting to be (easily) compatible with the Python C-API. No worries about the C stack at all. I mean, I could have used the C stack as the VM's stack but then you have to worry about blowing up the stack, not having access (without a bunch of hackery, looking at you scheme people) to the values on the stack for GC and whatnot and, I imagine, all the other things you have issues with but it's not needed at all, just make your own (or, you know, tail call) and pretend the C one doesn't exist. And I've started on another VM which does the traditional stack thing but it's constrained (by the spec) to have a maximum stack depth so isn't too much trouble.
- morcus 9mo agoAn interesting bit to me is that it compiles to (apparently) readable C, I'm not sure how one would use that to their advantage I am not too familiar with C - is the idea that it's easier to incrementally have some parts of your codebase in this language, with other parts being in regular C?
- zbendefy 9mo agoi think so. The biggest hurdle with new languages is that you are cut off from a 3rdparty library ecosystem. Being compatible with C 3rd party libraries is a big win.
- actionfromafar 9mo agoMakes it easy to "try before you buy", too. If you decide it's not for you, you can "step out" and keep the generated C code and go from there.
- morcus 9mo agoVery good point that I never considered! Thanks.
- forgotpwd16 9mo agoThis isn't a very sane plan. The ~300 LOC example mini_grep (https://github.com/z-libs/Zen-C/blob/main/examples/tools/mini_grep.zc https://github.com/z-libs/Zen-C/blob/main/examples/tools/min...) compiles to a ~3.3k LOC monstrosity (https://pastebin.com/raw/6FBSpt1z https://pastebin.com/raw/6FBSpt1z). It's easier to rewrite the whole thing than going from the generated code. At least for now, generated code shouldn't be considered something you're ever supposed to interact with.
- actionfromafar 9mo agoI looked at it primed for the worst by your comment, but it’s honestly not so bad. A lot of setup, data type code and what looks like overloads.
- v_iter 9mo agoSo, the point of this language is to be able to write code with high productivity, but with the benefit of compiling it to a low level language? Overall it seems like the language repeats what ZIG does, including the C ABI support, manual memory management with additional ergonomics, comptime feature. The biggest difference that comes to mind quickly is that the creator of Zen-C states that it can allow for the productivity of a high level language.
- johnisgood 9mo agoNim is a high-level language as well and compiles to C.
- the__alchemist 9mo agoOdin and Jai are others.
- Voycawojka 9mo agoDoes Odin compile to C? I thought it only uses LLVM as a backend
- sestep 9mo agoSame question but for Jai.
- deleted 9mo ago[deleted]
- throwaway17_17 9mo agoJai does not compile to C. It has a bytecode representation that is used primarily for compile time execution of code, a native backend used mostly for iteration speed and debug builds, and a LLVM target for optimized release builds.
- johnisgood 9mo ago
- alexpadula 9mo ago18 commits! I hope you keep up with the project, it’s really cool, great work.
- kreco 9mo agoThat's a very nice project. List of remarks: > var ints: int[5] = {1, 2, 3, 4, 5}; > var zeros: [int; 5]; // Zero-initialized The zero initialized array is not intuitive IMO. > // Bitfields If it's deterministically packed. > Tagged unions Same, is the memory layout deterministic (and optimized)? > 2 | 3 => print("Two or Three") Any reason not to use "2 || 3"? > Traits What if I want to remove or override the "trait Drawing for Circle" because the original implementation doesn't fit my constraints? As long as traits are not required to be in a totally different module than the struct I will likely never welcome them in a programming language.
- jdmichal 9mo agoC uses `|` for bitwise OR and `||` for logical OR. I'm assuming this inherited the same operator paradigm since it compiles to C.
- alfonsodev 9mo agoIs this the Typescript of C ?
- ramses0 9mo agoThe whole language examples seem pretty rational, and I'm especially pleased / shocked by the `loop / repeat 5` examples. I love the idea of having syntax support for "maximum number of iterations", eg: repeat 3 { try { curl(...) && break } except { continue } } ...obviously not trying to start any holy wars around exceptions (which don't seem supported) or exponential backoff (or whatever), but I guess I'm kindof shocked that I haven't seen any other languages support what seems like an obvious syntax feature. I guess you could easily emulate it with `for x in range(3): ...break`, but `repeat 3: ...break` feels a bit more like that `print("-"*80)` feature but for loops.
- zeknife 9mo agoRuby has a similarly intuitive `3.times do ... end` syntax
- ioasuncvinvaer 9mo agogo also has for range 5 { ... }
- blacksqr 9mo agoWhat's the performance hit?
- Lucasoato 9mo ago> Mutability > By default, variables are mutable. You can enable Immutable by Default mode using a directive. > //> immutable-by-default > var x = 10; > // x = 20; // Error: x is immutable > var mut y = 10; > y = 20; // OK Wait, but this means that if I’m reading somebody’s code, I won’t know if variables are mutable or not unless I read the whole file looking for such directive. Imagine if someone even defined custom directives, that doesn’t make it readable.
- andai 9mo agoGiven an option that is configurable, why would the default setting be the one that increases probability of errors? For some niches the answer is "because the convenience is worth it" (e.g. game jams). But I personally think the error prone option should be opt in for such cases. Or to be blunt: correctness should not be opt-in. It should be opt-out. I have considered such a flag for my future language, which I named #explode-randomly-at-runtime ;)
- miroljub 9mo ago> Or to be blunt: correctness should not be opt-in. It should be opt-out. One can perfectly fine write correct programs using mutable variables. It's not a security feature, it's a design decision. That being said, I agree with you that the author should decide if Zen-C should be either mutable or immutable by default, with special syntax for the other case. As it is now, it's confusing when reading code.
- Y_Y 9mo ago> I have considered such a flag for my future language, which I named #explode-randomly-at-runtime ;) A classic strategy! https://p-nand-q.com/programming/languages/java2k/ https://p-nand-q.com/programming/languages/java2k/
- psychoslave 9mo agoBut why put it as a global metaswitcher instead of having different type infered from initial assignation qualifier? Example: let integer answer be 42 — this is a constant set integer temperature be 37.2 — this is a mutable Or with the more esoglyphomaniac fashion cst ↦ 123 // a constant is just a trivial map st ← 29.5 // initial assignment inferring float
- forgotpwd16 9mo agoBasically C2/C3 but Rust influenced. Missed chance to call it C4.
- lerno 9mo agoI didn't see any similarities to C3, quite the opposite.
- seabrookmx 9mo agoIt's odd that the async/await syntax _exclusively_ uses threads under the hood. I guess it makes for a straightforward implementation, but in every language I've seen the point of async/await is to use an event loop/cooperative multitasking.
- sestep 9mo agoNoob question: if it just compiles to threads, is there any need for special syntax in the first place? My understanding was that no language support should be required for blocking on a thread.
- gmueckl 9mo agoAsync/await should do a little more under the hood than what the typical OS threading APIs provide, for example forwarding function parameters and return values automatically instead of making the user write their own boilerplate structs for that.
- maxbond 9mo agoOne advantage is that it gives you the opportunity to move to a more sophisticated implementation later without breaking backwards compatibility (assuming the abstraction does not leak).
- throwaway17_17 9mo agoI’d say that the point of async/await is to create a syntax demarcation between functions which may suspend themselves (or be suspended by a supervisory system) and those functions that process through completely and cannot be suspended (particularly by a supervisory system). The means to enable the suspension of computation and allow other computations to proceed following that suspension are implementation details. So, having an async function run on a separate thread from those functions that are synchronous seems a viable way to achieve the underlying goal of continuous processing in the face of computations that involve waiting for some resource to become available. I will agree that inspired by C#’s originating and then JavaScripts popularization of the syntax, it is not a stretch to assume async/await is implemented with an event loop (since both languages use such for implementation).
- Joker_vD 9mo agoFrom what I can see in the codegen, defer is not implemented "properly": the deferred statements are only executed when the block exits normally; leaving the block via "return", "break", "continue" (including their labelled variants! those interact subtly with outer defers), or "goto" skips them entirely. Which, arguably, should not happen: var f = fopen("file.txt", "r"); defer fclose(f); if fread(&ch, 1, 1, f) <= 0 { return -1; } return 0; would not close file if it was empty. In fact, I am not sure how it works even for normal "return 0": it looks like the deferred statements are emitted after the "return", textually, so they only properly work in void-returning function and internal blocks.
- ricardobeat 9mo agoDid you manage to compile this example?
- Joker_vD 9mo agoYes, actually: $ cat kekw.zc include <stdio.h> fn main() { var f = fopen("file.txt", "r"); defer fclose(f); var ch: byte; if fread(&ch, 1, 1, f) <= 0 { return -1; } return 0; } $ ./zc --emit-c kekw.zc [zc] Compiling kekw.zc... $ tail -n 12 out.c int main() { { __auto_type f = fopen("file.txt", "r"); uint8_t ch; if ((fread((&ch), 1, 1, f) <= 0)) { return (-1); } return 0; fclose(f); } }
- kv85s 9mo ago[dead]
- stevefolta 9mo agoNice! Compiles in 2s on my unexceptional hardware. But it lacks my other main desiderata in a new language: string interpolation and kebab-case.
- stevefolta 9mo agoOh, it _does_ have string interpolation, my bad. Sadly, not by default -- you still have to go back and add an "f" before the string once you've started typing it and then realize that you want an interpolated string. Also, it doesn't always work -- if I define two interpolated string variables in one function, GCC chokes in a way I'm not understanding. And every interpolated string variable consumes 4K of global memory.
- taolson 9mo agoThe author includes some easter-eggs (printing random facts about Zen and various C constructs) which trigger randomly -- check out the file src/zen/zen_facts.c in the repository...
- Dwedit 9mo agoI wonder how this compares to the Beef programming language. https://www.beeflang.org/ https://www.beeflang.org/ The Beef programming language was used to write Penny's Big Breakaway.
- Zambyte 9mo agoThe tagline also applies to C :-)
- aappleby 9mo agoExample at the top of the readme!
- Archit3ch 9mo agoAnswering the title, why not Julia?
- ekjhgkejhgk 9mo agoSame. I've been using Julia for almost everything for a long time now, and it's an amazing language. Very understated.
- Sieyk 9mo agoWhat has kept me from Julia is the abysmal start-up time (~3 sec from memory)
- eigenspace 9mo agoUnless you were using hardware from the 00's, or had a lot of packages in your startup.jl or something, I suspect your memory may be exaggerating quite a bit. That said, julia startup times definitely were a painpoint, but have improved quite a bit over the last few years.
- sebastianconcpt 9mo agoBut at that point why not Rust then?
- keyle 9mo agoImpressive repos. I've been toying with the ideas myself but it's hard to stay on track with this sort of extremely demanding task. I am however not exporting to C but to low level jit. A lot of the ideas in there are worth being inspired by.
- Panzerschrek 9mo agoYet another overly-hyped language with no practical benefits. Is it just another one better C?
- Panzerschrek 9mo agoIs it memory safe?
- rurban 9mo agoConstant hash seed? Never a good idea (std/core.zc)
- p0w3n3d 9mo agoThat's something I used to try to write, but failed due to complexity. A meta-preprocessor for C to make it a little bit more bearable... KUDOS
- deleted 9mo ago[deleted]
- t4eh0 9mo agoWhat about "Cex.C" and "dasae-headers"? they are integrated directly into the C ecosystem
- t4eh0 9mo agoThis feels like a mix of "Cex.C" and "dasae-headers" projects I've seen somewhere before - maybe it's just the Rust and Zig trend.
- RockieYang 9mo agonice to see it closure support.
- saidnooneever 9mo agoi really like this project. fot me its the next level to your own custom C lib. first your write 'tutorial C'. then after enough segfaults and double frees you start every project with a custom allocator because you've become obsessed with not having that again..., then you implement a library with a custom more generic one as you learn how to implement them, and add primitives you commonly build that lean on that allocator, it will have your refcouters, maybe ctors, dtors etc etc.. (this atleast is my learning path i guess? still have a loooong way to go as always!) i dont see myself going for a language like this, but i think its inspirational to see where your code can evolve to with enough experience and care
- mordv 9mo agoThis illustrates Greenspun's tenth rule very well.
- Kapendev 9mo ago> String Interpolation (F-strings) This is so nice. It's crazy how other low-level langs don't have it. I know Dlang and Rust have it. Maybe Swift too? The way Dlang does it is nice because you can do a lot of stuff with them at compile time.
- AIn0n 9mo agoVery similar to any other C-like languages compiling to C (like nim, V, and many smaller hobbyist ones), but I love the keyword "embed". It looks like unlimited potential for fast debbuging, and testing the code without writing boilerplate to read the file and so on.
- bloodyforestcat 9mo agoThe whole thing is vibe coded lmao