Hacker News new | ask | show | jobs
by scottlamb 263 days ago
> The argument for using Rust instead of a memory safe implementation of C is all about performance. And that’s not a bad argument! But we should be honest about it.

I think it might also be that people mostly consider languages from the perspective of what they'd write a greenfield codebase in. And if I'm gonna pay the GC cost, I'd much rather work with language/library body that doesn't have tons of ownership idioms that are basically irrelevant with a GC. So it's not Fil-C vs Rust directly; it's Fil-C vs Go (Go wins), then Go vs Rust (more interesting decision).

But for existing large C projects that are ancient enough that running on modern hardware far outweighs the new GC cost, and that are mature/minimally maintained so the development costs for a rewrite/translation won't ever pay off in future maintenance, I think Fil-C is an intriguing option.

btw, IMO Rust has more going for it than just the borrow checker.

1 comments

I think what you’re saying is true for the kind of software where it isn’t just greenfield but also doesn’t have to make deep use of preexisting system dependencies.

Like, say you’re writing a port daemon. Then your argument holds! And that’s admittedly a big category since it includes databases, application servers, and a lot of other stuff.

But say you’re writing an app that talks to systemd and your desktop shell and renders things and has a UI. If you do that in Go or Rust, you’re pulling in a ton of unsafe dependencies. But the Fil-C story is that you just compile all of that stuff with Fil-C and so there are no unsafe dependencies.

By the way, that’s not a fantasy but like mostly a reality. I have a Linux distro where all of userland is compiled with Fil-C and it works great!

Now you might say, why not rewrite all the deps in Go or Rust? The funny thing about that is you sort of can’t do that today since neither of those languages has dynamic linking. Fil-C supports dynamic linking just fine.

> Now you might say, why not rewrite all the deps in Go or Rust? The funny thing about that is you sort of can’t do that today since neither of those languages has dynamic linking.

I don’t know about Go, but that’s certainly not true for Rust. Dynamic linking is the norm in Rust; you can run `ldd` on any stock-built binary to see that it dynamically links to glibc (or libSystem or similar).

(It’s also common for Rust libraries to be distributed as shared objects with C APIs/ABIs — to my understanding, this is how virtually every incremental adopter of Rust has chosen to adopt it.)

When you do that, the ABI boundary around your shared library is unsafe.

So if you rebuilt userland with Rust and had the same layout of shared libraries then you’d have a massive amount of unsafe code

> So if you rebuilt userland with Rust and had the same layout of shared libraries then you’d have a massive amount of unsafe code

Sort of, but I think that’s misleading; you’d have a massive amount of safe code, scaffolded with unsafe ABI boundaries. That’s a problem, but it’s not really the same kind of attacker or fault surface as unsafe code in the libraries themselves.

It’s also a wholly solvable problem in the sense that Rust could define a stable non-C ABI. There just hasn’t been an extraordinary need for that yet, since most people who want to build Rust code into shared objects do want a C ABI.

> neither of those languages has dynamic linking

what do you mean by this?

Neither Go nor Rust define an ABI for themselves. They can use dynamically linked C code just fine but cannot link their own language with all (or even a reasonably broad subset) of its own features. This is not as bad in Rust, where you can fall back to the unsafe C ABI while still having safe Rust on either side, whereas Go cannot have two instances of its runtime active in the same process.

Compare this situation with Java/JVM or C#/.NET, both of which define their own ABIs albeit not for native machine code, or especially Swift, which defines its own native-code ABI.