Live data from Hacker News

Zig's Incremental Compilation Internals

mlugg.co.uk

201–210 of 292 posts

Re: Zig's Incremental Compilation Internals

#201
post #29

Earlier quoted context omitted.

Would you mind sharing some thoughts about fil-c? AFAICT its claims mostly check out so besides implementation details (GC?) it seems directionally good.

Okay so: in general, as a rule of thumb: anything that makes stuff have more memory safety is good. And experiments towards that end are also good. What I do not like, primarily comes down to how the project is talked about and marketed. First, because it promotes an "us vs them" mindset, instead of a "we're all trying to improve memory safety" mindset, and second, because in doing so, it also overstates its case. Th…

> First, because it promotes an "us vs them" mindset

I was always intrigued by the maturity about how the Rust team approached this sort of thing. IIRC years ago you and I had a back and forth on me thinking it would be helpful to have a "Why Rust is better than C++" type page.

Seeing an alternative approach from Andrew Kelley in recent weeks has really hammered home the value of the approach the Rust team took in terms of community building.

Re: Zig's Incremental Compilation Internals

#202

Earlier quoted context omitted.

Whats the point of evaluating technology from hello world programs?

Tbf, it's a useful indicator whether a language follows the "simple things should be simple, complex things should be possible" principle. The vanilla 'Hello World' should always be an example of the "simple things should be simple" part.

The typical Hello World implementation tends to reveal very little about the language, because their print/println/printf/whatever implementations have failure modes that are either impossible to handle or easily ignored (e.g. panicking, throwing exceptions or returning error codes which you can implicitly ignore without compilation error) which they frequently use to effectively hide the complexity inherent to the problem. Some examples of this:

The C Programming Language includes a Hello World example that calls printf without checking the return value and returns a success code from the main function regardless.

The first example I find when googling "java hello world" simply calls System.out.println and neglects to call System.out.checkError to see if it was successful before exiting with a success code. Some Java developers won't even know what I'm talking about here because it has never occurred to them that printing may fail in a way that can only be discovered through this weird checking mechanism.

Go's example from their getting started guide simply calls fmt.Println while ignoring the return values which include any error that may have occurred, and the program exits with a success code regardless.

The example from Rust by Example is at least correct and thorough in that it will predictably panic upon error when invoking the println! macro, which is documented, but will through that mechanism not give you the option to actually handle the error except by using a different mechanism which front-loads more of the complexity (e.g. writeln!(io::stdout(), "Hello World")? for something equivalent to the Zig example).

Of course for something as basic as Hello World it might be easy to tell whether it was successful through a quick glance at the output, but consider some of these limitations in a larger program.

So maybe there is more inherent complexity to this problem than a typical Hello World implementation will reveal. Add to that the complexity of Zig's new swappable I/O models and their Hello World isn't so absurd.

Re: Zig's Incremental Compilation Internals

#203

Earlier quoted context omitted.

Do you find most of your rust code is unsafe? Because I also find I do some unsafe stuff, because of the algorithms I work on I often end up with some unchecked array accesses and a couple of raw pointers into those arrays I pass around. But 98% of the code is safe and I find this makes it easier to reason about.

Yes, it's pron. Pron works on a JVM so he looks at everything from a language runtime lens. To him, the entire code base might as well be unsafe. The argument that you can contain unsafe in safe abstractions does not interest him, because of the nature of the projects he works on.

> To him, the entire code base might as well be unsafe.

Not at all. I would very much like the code to be safe, it's just that I reach for a low level language to get the thing that low-level languages are designed to offer me, which is control, and no language offers control and safety at the same time. So when the interesting parts of the code could be written in safe Rust, I have to give up control, and in that case I'd rather use a more convenient language that doesn't give me full control. And when the interesting parts of the code need full control, Rust doesn't give me safety anyway, and I still pay for its complexity. As to encapsulating unsafe, that doesn't help at all if the most tricky parts of the code are inside. What happens there is that Rust makes the hard parts harder and the easy parts easier, and for me that's a net negative.

Re: Zig's Incremental Compilation Internals

#204

Earlier quoted context omitted.

Tbf, it's a useful indicator whether a language follows the "simple things should be simple, complex things should be possible" principle. The vanilla 'Hello World' should always be an example of the "simple things should be simple" part.

The typical Hello World implementation tends to reveal very little about the language, because their print/println/printf/whatever implementations have failure modes that are either impossible to handle or easily ignored (e.g. panicking, throwing exceptions or returning error codes which you can implicitly ignore without compilation error) which they frequently use to effectively hide the complexity inherent to the p…

I mean sure, from a purely 'is this program correct' pov you're correct, but then a hello-world is mainly about "how do I get some frigging text to show up on the terminal", and how likely is that to fail anyway (at least I never had the canonical C hello-world fail on me).

Re: Zig's Incremental Compilation Internals

#205
post #143

Earlier quoted context omitted.

I originally came to Java because of the better performance it offered compared to C++ in large programs . The JVM is specifically designed to remove some of the fundamental performance overheads that low-level languages suffer from, and manifest especially when programs grow large (and a browser is quite large). So when someone talks to me about "GC languages" being slow and low-level languages being fast, I know th…

I don't think it's true that Java offers strictly more optimisation opportunities than low-level languages, but rather different optimization opportunities. C++ and Rust have other opportunities that Java does not generally have: - Explicit object lifetime and deterministic destruction. - Stack allocation by default. - Value types and direct embedding of values in data structures. - Precise control over data layout,…

> Stack allocation by default, Value types and direct embedding of values in data structures.

This used to be the big one, but not anymore: https://openjdk.org/jeps/401 (so Valhalla is integrating in JDK 28; it's not complete and this JEP is only the first step, but Java will have everything it needs on that front very soon.

> Precise control over data layout, alignment, padding, and SIMD-friendly representations.

Since the JVM controls layout, this is a point for Java.

> No mandatory tracing, write barriers, object headers, or garbage-collector scheduling.

Java doesn't require these things. JVM implementations choose to have them as an optimisation.

> Explicit object lifetime and deterministic destruction.

Hypothetically, this could have been an optimisaton opportunity. In practice, this is not a problem for Java but it is a problem for low-level languages, and especially Rust. The problem isn't knowing when an object's life is over, but needing to do something about it then and there. The whole idea of moving collectors (and arenas) is that it is more efficient to do nothing when an object becomes unreachable, and knowing when that happens doesn't help.

> And remember that GC is not free

Of course it isn't, but moving collectors are cheaper than free-list-based approaches, which is why we use them (most objects are never traced; those that are, are traced rarely etc.). On the whole, moving GCs are a speed improvement, reducing the overheads in C's runtime, and what they take in exchange is footprint (i.e. they use RAM chips as hardware accelerators). Now, that footprint cost could be expensive in smart watches and smaller devices, but in larger ones, the tradeoff is almost always worth it. I gave a talk about exactly that at Java One that should be up on YouTube eventually.

> Saying that "Low-level languages sacrifice performance for control" is also not true imo, since they can avoid allocation entirely, store data contiguously rather than as individually allocated objects, avoid all gc work, control cache behavior and eliminate pointer chasing, and importantly, guarantee hard or soft latency bounds.

I don't agree with that, and that's the very crux of my point. What you're really saying is that fine-grained control over the hardware lets a user who works hard enough to optimise their program to any level they choose. This does work well in small programs, but it fails in larger ones, and the JVM is designed to solve the performance issues that we C++ programmers experience in large programs. Over time, as programs grow and become more elaborate, it gets harder and harder to do those manual optimisations, which are very intrusive. E.g. you could perhaps use arenas in Rust more-or-less safely, and maybe Rust will make it easier in the future (right now the only language that makes that easy is Zig), but changing from no-arena to arena or vice versa, or finding out that you need special cases to some objects, requires a huge change to a low-level program. Similarly, trying to keep virtual calls to a minimum is very easy in the beginning, but becomes harder over time. So the idea that with enough control you can do anything is true in principle, but in practice it's very hard as programs evolve. The idea of modern runtimes is that you write the code naively, and the runtime performs global optimisations that help the average-case performance.

> I'm not seeing AAA game studios building their engines in Java. I don't see any OS's building their kernel (or anything really) in Java. If Java is faster than low level languages, why is that?

Much more performance-sensitive software is written in Java than in C++ these days, and your question assumes that the main thing that's important in these particular is speed, but that is not the case. What is the main thing kernels need to do? Directly control hardware. And what is the one thing that low-level languages are optimised for? Direct control over the hardware. Low-level languages fit the domain of OS kernels like SQL fits data queries; that's what they're for.

As for games, first, performance isn't the issue here. The most performance-critical parts of a game are not written in C++ but in CUDA, and the main important part for the CPU is a good algorithm for scheduling the data to the GPU, and that can be done in any language. What is very important for games is hardware support, and the JVM simply doesn't target most consoles. Second, games do care about latency, at least up to the length of a frame, and until very recently Java had GC pauses, and those could sometimes exceed the latency needed by games. GC pauses were removed in HotSpot only 3 years ago. So these are the reasons game engines are normally written in C++ (except, of course, for the most successful game in history, which is written in Java).

Re: Zig's Incremental Compilation Internals

#206

Earlier quoted context omitted.

I'm not exactly sure what you mean by "universal value", but I would say to be "table stakes" (i.e. not optional), it has to have overwhelming value. I think outside some fairly niche areas (e.g. programs that don't process untrusted data at all), it very very clearly has overwhelming value. Now you might argue that the other features of Zig, like `defer`, are so good that they reduce the chance of memory errors and…

His point is literally that writing a JVM (or any other language runtime) in Rust is unpleasant. He can't write a JVM without using unsafe. So his disagreement on the "table stakes" is that his "table stakes" require using unsafe Rust everywhere and from that perspective Rust is not that different from any other language. Hence the complaint about the lack of universality, which I personally consider weird. His point…

What makes a JVM a good fit for a low-level language is the need/utility for precise control over the hardware, but that's always the reason to want a low-level language (why would you use a low-level language if you don't want precise control over the hardware?). When Rust gives you safety it takes away much of that control, and when it gives you control it takes away the safety. Now, there could well be cases where this mix is fine - I've never worked on a browser, and Rust may well be the best language for writing browsers.

Re: Zig's Incremental Compilation Internals

#207

Earlier quoted context omitted.

The typical Hello World implementation tends to reveal very little about the language, because their print/println/printf/whatever implementations have failure modes that are either impossible to handle or easily ignored (e.g. panicking, throwing exceptions or returning error codes which you can implicitly ignore without compilation error) which they frequently use to effectively hide the complexity inherent to the p…

I mean sure, from a purely 'is this program correct' pov you're correct, but then a hello-world is mainly about "how do I get some frigging text to show up on the terminal", and how likely is that to fail anyway (at least I never had the canonical C hello-world fail on me).

What's the point of showing an example if it's incorrect? If someone asks "how do I get some frigging text to show up on the terminal" and the answer is incorrect, it's bad advice as far as I'm concerned.

> and how likely is that to fail anyway (at least I never had the canonical C hello-world fail on me).

I don't expect to know how likely writing to stdout is to fail and I don't think any answer to that question other than 0 really warrants ignoring the potential error if the correct result of invoking your program depends on it. For what it's worth, at least in Unix-likes, stdout could be pretty much anything. Writing to stdout could fail because a switch at the user's ISP is rebooting.

Re: Zig's Incremental Compilation Internals

#208

Earlier quoted context omitted.

The point is not that those specific implementations use unsafe Rust but to illustrate that to write even basic data structures you need unsafe Rust.

That's just false. You can use `Arc` or even one of the safe GC crates available, and get semantics like Java with no `unsafe`.

Yeah but that doesn't work for any kind of performant code which is the reason people who write those data structures use unsafe. This is one very annoying thing about Rust community. The language sucks for coding self-referencing data structures with unpredictable free patterns. This is a fact and the reason number of people on this very forum posted long articles about moving away from Rust for those purposes.

Your "actually you can" post is just misleading and will result in more people who will get burnt but the design of the language.

Re: Zig's Incremental Compilation Internals

#209
post #90
post #80

Earlier quoted context omitted.

Zig already uses arocc! https://codeberg.org/ziglang/zig/src/branch/master/lib/compi...

That's there for translate-c, it's not used for compiling C code (To be clear, squeek502 is a part of the Zig core team [0], so he knows what he's talking about :D) [0]: https://ziglang.org/news/welcoming-new-team-members/

my bad, thank you for pointing that out!

Re: Zig's Incremental Compilation Internals

#210

Earlier quoted context omitted.

Okay so: in general, as a rule of thumb: anything that makes stuff have more memory safety is good. And experiments towards that end are also good. What I do not like, primarily comes down to how the project is talked about and marketed. First, because it promotes an "us vs them" mindset, instead of a "we're all trying to improve memory safety" mindset, and second, because in doing so, it also overstates its case. Th…

I generally agree with all of this, but I'll add a few additional remarks. Because it's come up a bunch lately, I decided to do a bunch of code review/audit of the Fil-C codebase, and I'd say while it's got a lot of good bones, there's a long way to go to being a foundation I'd be ready to build on. I've reported a few UAF's upstream, and I've got a few PRs I'll add on, but if it only took me a day or two to find som…

First of all, it’s incredible that on a HN thread about a language that isn’t C, there are 46 mentions of Fil-C! You guys are obsessed!

I make bold claims because they hold water.

- You can at worst corrupt only the capability you’re pointing to.

- intra object overflows are almost never useful for memory corruption exploits unless they let you corrupt a pointer, and Fil-C prevents that from being useful because you cannot corrupt the capability.

- the zunsafe api is basically unused. One library uses it (OpenSSL) for good reasons. This is in contrast to widespread use of the unsafe keyword in Rust, beyond just one library for a narrow purpose.

Thanks for reporting bugs. Worth noting that they require doing things that extant C code never does. It’s good to fix those, but the true threat model of any memory safe language is not to sandbox a malicious programmer, but to protect the program of a normal programmer against a malicious user

Post reply on HN