7 ms·
I was just thinking that we were overdue for a Fil-C post on HN.
by LugosFergus 2mo ago
I was just thinking that we were overdue for a Fil-C post on HN.
- quotemstr 2mo agoEvery one of these posts is the same. There's this weird blindness to the problems and imperfections in Fil-C --- just shouting down. It reduces my confidence in Fil-C as a whole. Rust, for all its faults, at least engages with its critics. I've long faulted Rust's use of Result over exceptions, for example, but the maintainers at least acknowledge that other options exist and each has trade-offs. Not Pizlo and his fans. To be clear, I like Fil-C. It's a practical implementation of something that should have existed a long time ago. And Pizlo is, in fact, a great programmer. It just rubs me the wrong way that he can't be content with having done excellent work --- he has to claim things that his system doesn't provide (like memory safety under data races --- minor fault, but still) and claim that other systems are worse in ways they are not (e.g. with respect to Rust having unsafe blocks). Is genuine excellence not enough? Why must he persist in claiming a false perfection?
- jagadaga 2mo ago>I've long faulted Rust's use of Result over exceptions Why?
- AlotOfReading 2mo agoNot the person you're asking, but result types pessimize code more, add register pressure, use more icache for largely dead code, etc. They're arguably noisier at the source level too. That said, I've spent too much of my life chasing implicit control flow to accept exceptions. Heck, C++'s "noexcept" is a strong argument against exceptions all by itself.
- anon-3988 2mo agoI don't understand why Result type is necessarily slower. Result that simply bubbles up is basically an exception, no?
- AlotOfReading 2mo agoYou need instructions to check the result type, and a bit somewhere to store whether it's valid. Most exceptions only add extra instructions during throws/unwinding. There may or may not be an overall reduction in code size, depending on how many checks you have vs table entries.
- jagadaga 2mo agoIn theory, a compiler can figure out that you don't need that in some cases.
- pjmlp 2mo agoC++ noexcept exists because the way C++ evolved, it is no argument against exceptions. Exceptions came to be during the 1990's, as the C++ARM to C++98 standardisation process was taking place. Naturally during the early days C++ compilers lacked exceptions, as CFront was introduced without them. Then we had the C folks that were migrating to C++. When C++ compilers finally supported exception, compilers vendors introduced the non standard switch to disable them, so that existing code could still compile with the expected behaviour. The standard itself does not acknowledge this as allowed. This feature was naturally misused by the anti-exception folks, same applies to how RTTI came to be. So noexcept is a way to be able to write code to appease both camps, while surfacing what variant was chosen by the programmer. From my point of view allowing disabling exceptions in first place was a mistake, those folks should have moved back to C, or fixed their code.
- jagadaga 2mo ago> result types pessimize code more What does it mean? > They're arguably noisier at the source level too. But they are more explicit, which means there will be fewer bugs in your code.
- MrBuddyCasino 2mo ago> That said, I've spent too much of my life chasing implicit control flow to accept exceptions. Yes. This is why unchecked exceptions are annoying. Checked exceptions are a „failed experiment“ anyway. A result type (or even Go‘s err) with forced error handling meaningfully increases the robustness of a program in my experience.
- _flux 2mo agoMy view is that Java's checked exceptions failed in big part because Java didn't have type variables back then; after all, polymorphic Result types are not that much different from checked exceptions. I haven't written any Java since it has gained those, so I suspect there might be other aspects making it awkward. And it still would lack exhaustiveness checking that e.g. Rust has.
- nu11ptr 2mo agoChecked exceptions were actually the "right way" to do exceptions (if there is such a thing), the problem was just that developers hated them, but I think that draws the wrong conclusion. That tells me their syntax/usage was seen as too much forced boiler plate making code unwieldy, not that they didn't have benefits for correctness (something often not appreciated until years later). Unchecked exceptions lead to unhandled exceptions at runtime. We've all seen screens with Java programs running with tons of exceptions in the log, or worse, that crash with unhandled exceptions. This is the result of the unchecked exceptions mess, which is why I won't use languages that use them for routine error handling for anything more than trivial programs.
- MrBuddyCasino 2mo ago> developers hated them, but I think that draws the wrong conclusion Exception handling is just annoying from a syntax perspective. Also checked Exceptions have the problem that they bubble up types that a different layer shouldn’t even be aware of due to exception chaining (cause of a cause etc), unless you carefully re-throw them, which nobody did. Lower ceremony errors are just better to deal with.
- wasmperson 2mo agoThe worst part about rust not having exceptions is that it actually does have exceptions, you just shouldn't use them. All the downsides and none of the benefits: https://smallcultfollowing.com/babysteps/blog/2024/05/02/unwind-considered-harmful/ https://smallcultfollowing.com/babysteps/blog/2024/05/02/unw...
- pjmlp 2mo agoJust like on Go's case, panic/recover are exceptions with bad ergonomics.
- kibwen 2mo agoNo, Rust does not have exceptions. Rust has unwinding, if you choose to compile your program with support for it, which you are free not to, and is trivially achieved by a single flag.
- wasmperson 2mo agoIt's hard for me to think of a definition of "exception" which doesn't include Rust's panics: use std::panic::catch_unwind; fn throws_exception(){ panic!("hello"); } fn main(){ match catch_unwind(|| { throws_exception(); println!("Never reached"); }) { Ok(_) => (), Err(e) => println!( "threw an exception: {:?}", e.downcast_ref::<&'static str>().unwrap()) } } I can disable exceptions in rustc, but I can't disable the influence they have on language and library design (as detailed in the link I posted). Exceptions are the main reason you can't temporarily move something out from behind an exclusive reference, or return an error code from a Drop impl. Heck, Rust wouldn't even need destructors if it weren't for exceptions: the compiler could just tell you when you forgot to free something.
- dundarious 2mo ago> claim that other systems are worse in ways they are not (e.g. with respect to Rust having unsafe blocks) If considering only "safety", then Fil-C is more safe than any Rust containing unsafe blocks, no? With the usual caveats about whether an abort() is safe.
- NobodyNada 2mo agoMachine code is unsafe, so any memory-safe language must necessarily be built on some unsafe code somewhere. Safety is always conditional on the underlying unsafe implementation having no bugs. With Fil-C, the "unsafe blocks" live entirely within the compiler and runtime. With Rust, the unsafe foundation is the Rust compiler and standard library, as well as any unsafe code within your application or dependencies. So either way you're in the same situation of relying on the correctness of the unsafe code you depend on. But there are two major differences: - Unsafe code can be written in Rust, instead of inside the compiler. This is much easier to write and to review for correctness. - People other than Fil are allowed to write unsafe Rust. This is what Fil's point is about, and yes, it allows you to opt-in to increasing your attack surface by trusting unsafe code written by yourself or your dependents. Rust allows the user to choose where they draw the trust boundary, and Fil-C does not. It's true that Fil is probably better than I am at writing unsafe code. So "Fil-C is safer than Rust" is true in that sense. But Fil-C is certainly not safer than safe Rust. And sure, you can't run all the Rust code in the world if you compile with '--deny unsafe_code'; but Fil-C can't run all the C code in the world either. Unsafe Rust is rarely needed, mostly only if you want to do pointer crimes or FFI, and Fil-C doesn't support a lot of (perfectly legal) pointer crimes and FFI either.
- flumpcakes 2mo agoThere are no 'unsafe' blocks in Fil-C. I think you trying to conflate 'unsafe blocks' with the fact that there might be compiler errors which might break 'safety'? Which is equally true in any system including Rust.
- NobodyNada 2mo ago
- pizlonator 2mo agoIf you think you like Fil-C but aren’t able to see the specific way in which it’s better than Rust (more comprehensive safety), then what is it that you’re liking?
- NobodyNada 2mo agoNot the parent, but: I strongly dislike this framing of "Fil-C is better than Rust" or "Rust is better than Fil-C". This is apples-to-oranges; users will almost never be comparison-shopping between the two because they address almost entirely different problems. There are roughly two categories of Rust user: 1. People who are using Rust for application development. Most of these users write zero unsafe blocks in their careers. For these users, "memory safety" was probably not a strong reason to pick Rust, because there are a wealth of other memory-safe application development languages out there. 2. People who are using Rust for systems programming (i.e. programming under resource or environment constraints). These users may write unsafe for performance reasons, or to do things like hardware MMIO; and they're using Rust over C/C++ either for security or just because the tooling is nicer. The first category of user is unlikely to consider C for application development in this decade; they're going to be comparing Rust against Go or Java or Node.js. Fil-C solves the security problem of memory safety, but it does not free the developer from the difficulty of having to manually write memory-safe C code; their program will just crash if they get it wrong. The second category of user cannot use Fil-C because of its performance overhead, runtime requirements and/or lack of escape hatches for MMIO/FFI. Where Fil-C does shine is for legacy application software written in C. Here, it's a free lunch: a way to harden the massive amount of existing software without an expensive rewrite. I would love to see distros shipping pizlonated coreutils, ffmpeg, systemd, curl, sudo, postgres, etc., anything that has a big attack surface, but does not need to be memory-unsafe. This is a problem I care about a lot, and your work here is truly a monumental advancement in the field. Comparisons to Rust sell it short by inviting endless debate on problems largely tangential to Fil-C.
- pizlonator 2mo agoI’ve never said that Fil-C is better than Rust full stop. I have articulated the specific ways that Fil-C is better. And I’ve articulated the specific ways that Rust is better. You’ve enumerated some of those reasons from your perspective, though I disagree on the details. I like those kinds of conversations. We shouldn’t shy away from them as a community. They help us grow a shared understanding of the tech
- uecker 2mo agoHe claims the system provides memory safety under data races. Does it not?
- brabel 2mo agohttps://news.ycombinator.com/item?id=49044561 https://news.ycombinator.com/item?id=49044561
- mshroyer 2mo agoHe's been especially arrogant and dismissive on X. I'm very glad Fil-C exists, but his behavior makes me doubt the whole project.
- metaltyphoon 2mo agoMark? AwareDigital 2013?
- mshroyer 2mo agoHey drop me an email
- mshroyer 2mo agoTo be concrete and hopefully more constructive with my criticism, he's prone to saying things like "Fil-C is safer than Rust": https://x.com/filpizlo/status/2053351119095791995 https://x.com/filpizlo/status/2053351119095791995 And "Rust let’s you corrupt memory / Fil-C doesn’t.": https://x.com/filpizlo/status/2079253367587737841 https://x.com/filpizlo/status/2079253367587737841 These are false claims. The following compiles and runs fine with Fil-C, happily corrupting memory in a way that a safer language like Rust would not allow: #include <stdint.h> #include <stdio.h> struct Account { unsigned char name[8]; uint32_t privileged; }; void write_name(struct Account *account, size_t index, char value) { account->name[index] = value; } int main(int argc, char* argv[]) { struct Account acct = { .name = "foobar", .privileged = 42, }; write_name(&acct, 8, 1); printf("privileged = %d\n", acct.privileged); return 0; } His claims about Fil-C being safer than Rust seem to hinge on Fil-C's ability to make safe-er an entire application stack, compared to a hypothetical Rust application that links to C dependencies which (currently) can't be compiled with Fil-C. This is true as far as it goes, but it's a far cry from justifying a blanket statement like "Fil-C is safer than Rust".