3 ms·
Hey 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 a
by nickmqb 8y ago
Hey 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.
- nickmqb 8y agoYou're correct that Muon wouldn't catch that bug, but I think one can make a pretty strong case that it's an anti pattern to use unsigned integers for that kind of stuff anyway. It's actually the reason that the Muon standard library defines Array.count and List.count as _signed_ integers. Even though these fields should clearly never be negative, having them be unsigned would invite exactly the kinds of bugs that you demonstrate in your test case.
- int_19h 8y agoAs you say, it's off by default in ReleaseFast, which sounds like what most projects would use for shipping code, and what most users would be running. So the safety checks would mostly be confined to debug builds - and from experience with C++, that's not enough. Especially for integer overflow, where it's too easy to write code that works correctly on most inputs, but fails for large values - so those bugs usually manifest in real world use rather than in testing. I agree that it's better to panic rather than wrap around by default, so long as panic is guaranteed.
- AndyKelley 8y agoThanks for the compliment. I look forward to watching Muon's progress, and stealing all your good ideas! (I mean that in a friendly way; both Zig and Muon are MIT licensed and of course Zig's ideas are all up for grabs too)
- nickmqb 8y agoThat's entirely fair game, good luck to us both! ;)