4 ms·
There's quite a bit of overlap with Zig (and maybe even more with V, which recently appeared on HN). Some differences between Muon and Zig: - Syntax/ergonomic
by nickmqb 8y ago
There's quite a bit of overlap with Zig (and maybe even more with V, which recently appeared on HN).
Some differences between Muon and Zig:
- Syntax/ergonomics: Muon has return type inference, Go-like syntax/no semicolons, no "pub fn"s anywhere, reference type notation.
- Memory management philosophy: Muon makes it easy to allocate memory, e.g. via "new" operator and fully customizable thread-local allocators.
- Minimal error handling: Muon provides abandonment (i.e. panic), but no extra error handling features like Zig does.
- Muon is a more minimal language in general: no meta programming (yet, at least), no async, no bit fields.
Zig is a lot more mature though, so I'm trying to catch up as fast as I can ;).
- AndyKelley 8y agoI'm jealous of that self hosted compiler! For Zig I've mandated that we have to forever maintain both the stage1 C++ compiler as well as the self-hosted one (which is not feature complete yet). Also I have some bad news for you... > One major caveat: after the above stages have finished, a C compiler still needs to run to generate the final binary, which usually takes up the most time. The LLVM backend will (hopefully) reduce this. Nope. LLVM is about 80% of the time that it takes to compile Zig code. Other language authors have found similar results. See for example http://pling.jondgoodwin.com/post/compiler-performance/ http://pling.jondgoodwin.com/post/compiler-performance/ Anyway, Godspeed. I'll be watching Muon with interest :-) Edit: one more question, if I may: > No undefined behavior. Undefined behavior can lead to various, hard-to-spot, bugs. In Muon, all behavior, including platform-specific behavior, is defined. > The compiler currently outputs C code.This means that we inherit C's undefined behavior model, which goes against the goals listed above! An LLVM backend is in the works which will avoid any undefined behavior. > High performance. Strive for parity with C. How are these things to be reconciled? First of all LLVM IR and C have basically the same undefined behavior model. In both C and LLVM IR it's possible to output well-defined code. But more confusing to me is how it's supposed to be fast, if everything is defined? For example: https://godbolt.org/z/7d8RLG https://godbolt.org/z/7d8RLG export fn add1(a: i32, b: i32) bool { return (a - b) > 0; } export fn add2(a: i32, b: i32) bool { return (a -% b) > 0; } In this Zig code, we see 2 implementations of a function. `add1` has undefined behavior if `a - b` overflows. `add2` has defined behavior: wraparound arithmetic. The assembly code, with optimizations on: add1: cmp edi, esi setg al ret add2: sub edi, esi test edi, edi setg al ret You can see that the version with undefined behavior has 1 fewer instruction. How can you expect to compete with C (or Zig's) performance without undefined behavior?
- nickmqb 8y agoHey Andrew, I really like your work! In addition to the Muon compiler I'm still maintaining a C# interpreter which is used for bootstrapping (just so there's always a safe bootstrapping path), so there's some extra work there. The interpreter only supports a subset of the language, which means that I have to selectively avoid a few language features in the compiler. It's not too bad though. I've been digging into LLVM over the last week, and I'm slowly coming to that conclusion. I'm tempted to add an x86_64 backend, but there's already so much work to do ;). Perhaps WASM would be an interesting target to add. It's new so it doesn't have too much cruft yet, and it may actually work as an intermediate representation (haven't looked at this at all though). Re: edit. Integer overflow will be defined as 2-s complement wraparound. In your example, Muon would always emit the extra instruction, even in optimized builds. I must admit that I don't have a good intuition yet for how often these cases happen. If it means that Muon is leaving significant performance gains on the table, I'd be willing to consider adding a construct that would allow undefined behavior for very specific sections of a program to enable these optimizations. But by default, there would not be any undefined behavior.
- int_19h 8y agoFor a low-level language like this, I think you have to pretty much assume from the get go that anything that has runtime overhead needs an escape hatch, because somebody somewhere might need it. For example, the ability to explicitly request variables or allocated memory to not be zero-initialized can come in handy. I agree that it's better to default to well-defined, though. That's one thing that I found somewhat questionable about Zig arithmetic operators - why is the shortest and the most obvious one UB on overflow? Sure, it's like C, but in this case that's exactly the problem. IMO, doing things in the most obvious way should always emphasize correctness over speed.
- AndyKelley 8y agoActually arithmetic is even less defined in Zig than in C! For example, addition with unsigned integers in C is well-defined, but it is (safety-protected) undefined behavior in Zig. I actually agree with you that the most obvious way should emphasize correctness over speed, and that's why +, -, /, and * operators have language-level assertions to protect against integer overflow - which is almost always a bug. If Muon only has well-defined arithmetic, then it would not be able to catch this bug: const std = @import("std"); test "contrived example" { const income = 1000; const taxes = 1009; const cost_of_living = 300; std.testing.expect(!isValidSalary(income, taxes, cost_of_living)); } fn isValidSalary(income: u32, taxes: u32, cost_of_living: u32) bool { return (income - taxes) > cost_of_living; } In Zig the output is: Test 1/1 contrived example...integer overflow /home/andy/dev/zig/build/test.zig:11:20: 0x204267 in ??? (test) return (income - taxes) > cost_of_living; ^ /home/andy/dev/zig/build/test.zig:7:38: 0x2040d8 in ??? (test) std.testing.expect(!isValidSalary(income, taxes, cost_of_living)); ^ It shows you right where the bug is. If the `-` was defined to be twos complement wraparound, isValidSalary would silently return the wrong data! Note that if you build this zig code in ReleaseFast or ReleaseSmall mode, it would be actually undefined behavior. ReleaseSafe is available as a build mode that has both optimizations and safety on.
- nickpsecurity 8y agoGood luck on your language. It's pretty interesting. If LLVM is too heavy, you might want to check out QBE: https://c9x.me/compile/ https://c9x.me/compile/