Hacker News new | ask | show | jobs
by tialaramex 68 days ago
So, a few things, some of which others have touched on:

1. Fil-C is slower and bigger. Noticeably so. If you were OK with slower and bigger then the rewrite you should have considered wasn't to Rust in the last ten years but to Java or C# much earlier. That doesn't invalidate Fil'C's existence, but I want to point that out.

2. You're still writing C. If the program is finished or just occasionally doing a little bit of maintenance that's fine. I wrote C for most of my career, it's not a miserable language, and you are avoiding a rewrite. But if you're writing much new code Rust is just so much nicer. I stopped writing any C when I learned Rust.

3. This is runtime safety and you might need more. Rust gives you a bit more, often you can express at compile time things Fil-C would only have checked at runtime, but you might need everything and languages like WUFFS deliver that. WUFFS doesn't have runtime checks. It has proved to its satisfaction during compilation that your code is safe, so it can be executed at runtime in absolute safety. Your code might be wrong. Maybe your WUFFS GIF flipper actually makes frog GIFs purple instead of flipping them. But it can't crash, or execute x86 machine code hidden in the GIF, or whatever, that's the whole point.

6 comments

Yes it's slower, but it works. It's being built by one single dad who focused on compatibility before speed.

I'm not convinced that tying the lifetimes into the type system is the correct way to do memory management. I've read too many articles of people being forced into refactoring the entire codebase to implement a feature.

You initially said that rewriting in Rust "seems stupid" based on what Fil-C provides, and someone pointed out technical reasons why it still might be useful in some circumstances. It's great that a single dad is able to build Fil-C on his own, and you're certainly entitled to the opinion that you don't like the idea of lifetimes in the type system, but it's genuinely hard to tell if there's a specific technical point you're trying to make or you dislike Rust so much that you're interpreting someone disagreeing with you about whether Fil-C obviates it as somehow being a personal attack on the author.
I can tell you that it's not that he's setting aside speed -- the fact that it's as fast as it is is an achievement. But there is a degree of unavoidable overhead -- IIRC his goal is to get it down to 20-30% for most workloads, but beyond that you're running into the realities of runtime bounds checks, materializing the flight ptrs, etc.
20% to 30% slower would be amazing for all the extra runtime work that is required in my limited understanding. This would be good enough for a whole lot of serious applications.
> built by one single dad

Not some random dad, but a GC expert and former leader of the JavaScript VM team at Apple.

> tying the lifetimes into the type system is the correct way to do memory management.

Type systems used to be THE sexy PL research topic for about twenty years or so, so all the programming languages innovation has been about doing everything with type systems.

I think the core advantage of Fil-C (that Java and C# don't have) is that it moves the decision between security and performance to the user, not the programmer.

Imagine you're writing a library for, let's say, astronomical and orbital calculations. Writing it in Java means that it's always going to be slow. If you write it in C, NASA may decide to compile it with a normal compiler (because it won't ever be exposed to malicious inputs), while an astronomy website operator may use the Fil-C version for the extra security, at the cost of having to use slightly more computing resources, which are abundant on Earth.

This doesn't negate the advantages of Rust, which lets you get speed and performance at the same time.

> Fil-C is slower and bigger

It's not any slower or (proportionally) bigger compared to the experience you would have had 20 years ago running all sorts of utilities that happen to be the best candidates for Fil-C, and people got along just fine. How fast do ls and mkdir need to be?

I think the problem with this logic is that it views language performance on an absolute scale, whereas people actually care about it on a relative scale compared to how fast it could be.

If you tell your boss "We spent $1m on servers this month and that's as cheap as its possible to be" he'll be like "ok fine". If you say "We spent $1m on servers this month but if we just disable this compiler security flag it could be $500k." ... you can guess what will happen.

(Counterpoint though: people use Python.)

But counter-counterpoint: Rust does so much more than preventing runtime memory errors. Even if Fil-C had no overhead (or I was using CHERI) I would still use Rust.

> Rust does so much more than preventing runtime memory errors.

It sure does. Like making your build times slower (and bigger) than if you were using the equivalent tooling for Pascal, C, or Zig.

> than if you were using the equivalent tooling for Pascal, C, or Zig.

I think GP is talking about not-directly-related-to-safety things like sum types/pattern matching/traits/expressive type systems/etc. given the end of that paragraph. I don't think you can get "equivalent tooling" for such things the languages you list without raising interesting questions about what actually counts as Pascal/C/Zig.

I know what they were talking about. It was clearly intended to be a cheerfest for Rust.

> I don't think you can get "equivalent tooling" for such things the languages you list without raising interesting questions about what actually counts as Pascal/C/Zig.

I said builds. All of the languages I mentioned have "equivalent tooling" for that (i.e. compilers—to produce builds for the programs you choose to write in those languages).

> I said builds. All of the languages I mentioned have "equivalent tooling" for that (i.e. compilers—to produce builds for the programs you choose to write in those languages).

Oh, my mistake. Given the context I thought you were talking about some hypothetical tooling that gave you something approaching Rust's feature set.

I used to have one hour builds with C back in 1999 - 2002, for each of our target platforms, Aix, HP-UX, Solaris, Windows NT/2000, Red-Hat Linux, multiplied by Informix, Oracle, Sybase SQL Server, MS SQL Server, ODBC bindings.

A new product release would take a full day.

Nobody is saying Rust is perfect. I could point out many many flaws in Pascal, C and Zig too.

Besides Rust's compile time is actually fairly reasonable these days. Certainly not fast, but better than C++ and people have tolerated that for decades, so it's hardly a deal-breaker.

> I could point out many many flaws in Pascal, C and Zig

Yes. They're flawed. Everyone knows, but great detective work.

> Rust's compile time is actually fairly reasonable these days. Certainly not fast, but[…]

That's not reasonable.

Golang's compile times with the official toolchain are fast, despite the compiler being self-hosting and all the criticisms about the suboptimal code that its emitter produces. So with the official golang compiler being one such low-quality binary, by any reasonable measure, one should be able to expect the official Rust toolchain to be at least as fast. (Unless the explanation for that is as simple as that they just never give a shit about compile times. And I gotta say, I'm kind of getting the feeling that that might be the case. But it's still early days—Rust is a brand-new project after all—so maybe we should wait until it's at least a few years old before we come to any conclusions.)

And none of this addresses the demands on other resources, like memory—which was somehow deemed important somewhere near the root of this thread. (I guess that's not the case anymore, somehow.)

It's not that they don't care about compile times. Clearly they do. It's just that a lot of decisions were made that favour other things over compile time (e.g. runtime performance).

> That's not reasonable.

Most people think it is. You're in the minority there.

buy that logic (which I somewhat agree with), we should be rewriting all of these tools in C# or some similar native gc'd language. C and rust both take on a ton of complexity to squeeze out the last 2x of speed, but if we no longer care about that, we should drop C in a heartbeat
No, rewriting in any language is bad by itself. What Fil-C gives you is that you don’t need to rewrite old programs. You spend zero effort, and immediately your battle-tested program is memory safe and free of any potential future vulnerabilities. With Rust you spend man-years on a rewrite, and as a result you have a new untested program full of subtle bugs, which you need to spend another 10 years of real-world use to uncover.
Rewriting in c# is a lot more work than recompiling. That’s the point.
> the rewrite you should have considered wasn't to Rust in the last ten years but to Java or C# much earlier.

That doesn't quite make sense. The point of Fil-C, is to not have to rewrite in any other language, because it's still C. But now, there are safety benefits, though there is a trade-off with size and speed. Even in that context, size and speed, it can be very acceptable to many people and Fil-C will improve in that department as time goes on.

> Rust is just so much nicer.

That clearly is your own personal opinion that not everyone shares. There are many people who do not like Rust.

All of these didn’t prevent Go from competing with Rust and I’m guessing that Fil-C will be the better choice in some cases.

Rust has managed to establish itself as a player, but it’s only the best choice for a limited amount of projects, like some (but not all) browser code or kernel code. Go, C++, C with Fil-C) have solid advantages of their own.

To name two:

* idiomatic code is easier to write in any of these languages compared to Rust, because one can shortcut thinking about ownership. Rust idiomatic code requires it.

* less effort needed to protect from supply-chain attacks

To handle supply chain attacks, you need to know where yiur code comes from. That is often not a given when working with languages where it is easier to copy and paste in code from random other projects.

I have seen so must stuff copy and pasted into projects in my life, its not funny. Often it is undocumented where exactly the code comes from, which version it was taken from, how it was changed, and how to update it when something goes wrong.

When code is not copy and pasted it is over rewritten (poorly).

Code sharing does have its benefit. So does making it obvious which exact code is shared and how to update it. Yes, you can overdo code sharing, but just making code sharing hard on the tooling level does mote to hide supply chain security issues than it does to prevent the problem.

I doubt that ideomatic code is easier to write in C once you switch to Fil-C. Your code will just get killed by the runtime whenever it does something it should not do (and the compiler does not catch). You need to think about that stuff when your runtime enforces it.
Indeed, however Rust solves two problems in one language, the safety of managed languages, without having to use any form of automatic resource management, even if reference counting library types might be used, additionally.

As my comment history reveals I am more on the camp of having rewrites in Go (regardless of my opinion on its design), Java, C#, Haskell, OCaml, Lisp, Scheme,... Also following experiments of Cedar, Oberon, Singularity, Interlisp-D, StarLisp,....

However you will never convince someone anti-automatic resource management from ideological point of view.

Now would someone like that embrace Fil-C, with its sandboxing and GC? Maybe not, unless pushed from management kind of decision.

They would probably rewrite in Rust, Zig, Odin,... if those are appealing to them, or be faced with OS vendors pushing hardware with SPARC ADI, CHERI, ARM MTE,... enabled.

> However you will never convince someone anti-automatic resource management from ideological point of view.

It's generally accepted that 'explicit is better than implicit' and what you want in the end is deterministic, machine checked resource management. Automatic resource management is a subset of machine checked resource management. There is a large, somewhat less explored space of possibility (for example seL4 lives in this space) where you have to manually write the resource declarations and either the compiler or some other static analysis checks your work.

Except languages like Rust and C++, are full of implicit behaviour, so it is kind of interesting argument.

Even C has its implicit moments, with type conversions, signal handling, traps, setjmp/longjmp possibly hidden in libraries, thread handling across forks,

The fundamental question is that if an address is “safe” is a runtime thing, which in some cases you can decide it in compile time but not always. To force that during coding is just handicapping oneself to be “safe”. Which you can do the same in C (or mostly any language if you want it)
The languages we're discussing here are high level - like C - and so they don't have addresses like the machine code, they have pointers. With pointers we're back to the compiler needing to know if they're valid - if you delay until runtime you lose not safety but performance before the compiler optimises based on knowing whether values can be modified via a pointer and if that's only decided at runtime we cannot perform these optimisations so now our program is slower or bigger or both.