Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

(By the way, Hacker News doesn't support markdown; indent your code by two spaces, rather than using fences. https://news.ycombinator.com/formatdoc )

Just a few small things:

> This is a huge one for me, and I really don't understand why Rust didn't jump on this earlier.

Doing this well is not easy. Exposing a full language at compile time isn't a difficult feature, but doing compile-time execution in a sound, safe way is not simple. For example, cross compilation becomes more of a thing. It is easy to accidentally break the type system. I don't actually know how Zig implements comptime, but I expect given Andrew's chops, it's probably in a good way.

(And, one can argue that there are pros and cons here too, the article gets into them a bit. Doing everything this way has significant drawbacks, as well as significant pros.)

> I'm not sure what to say about this, except that it's surprising that there seem to be a lack of voices about this in the Rust community. How can anyone comfortably write `unsafe` code without knowing what the rules are? Especially when the compiler is so "good" at depending on the "rules"? I don't understand. I have pretty limited experience with unsafe, but I have written some, and was often confused about which bugs were my logic bugs and which were the compiler assuming I didn't break some rule I didn't know about. Combine this with a poor debugging story overall, and you have a pretty miserable experience programming.

There's just not a lot to say. The exact details are being worked on. This takes time. The team isn't going to make rules that invalidate large swaths of existing code, and has a history of making compatibility warnings with a long time before things break.

There is a fairly clear list of "this is absolutely not acceptable," and a bunch of "it depends...".

It's also just that the vast majority of people never need to reach for unsafe in the first place, so it isn't a huge pressure on a lot of people.



> doing compile-time execution in a sound, safe way is not simple. For example, cross compilation becomes more of a thing. It is easy to accidentally break the type system.

Why? I don't think I've ever seen a concrete example of why this isn't simple (but I'm not really a compiler person, so there might be!). I can imagine plenty of ways of doing Bad Things, like adding compiler flags based on what day it is, but I can't immediately see why this would _break_ anything. What do you mean by breaking the type system? Accidentally getting non-typechecked code in the compiler, or running into problems with the compiler thinking two equal types are distinct?

> There's just not a lot to say. The exact details are being worked on. This takes time.

I understand and appreciate this! Maybe I should've phrased myself better: I don't understand how people are using `unsafe` today successfully when something as fundamental to the Rust language model such as aliasing isn't really defined properly yet. It sound like people writing books without the rules on verb conjugation being really set. It sounds to me like plenty of the unsafe code out there might end up breaking at some point, and that, by extension, all other safe code out there is basically built on extremely shaky grounds.

I might be overreacting here though, since I don't write a whole lot of Rust anymore and am pretty distanced from the community. Considering their track record, I'm sure it'll turn out just fine.

---

> (By the way, Hacker News doesn't support markdown;

Ah! It's always tricky to remember which places support what syntax with these things. Thanks!


> Accidentally getting non-typechecked code in the compiler, or running into problems with the compiler thinking two equal types are distinct?

Yes, this sort of thing. Basically, you have to have this be deterministic, or you end up with very strange possibilities, possible miscompilations, and in the best case, confusing errors. One option is to simply accept that these things can happen. Another is to restrict what you can do at compile time to ensure that they can't.

An extremely simple example is cross compiling. In Rust, usize is dependent on the architecture you're compiling for. A very simple "just compile and run the program, get the answer, and use it" implementation of compile-time execution will produce a usize of the size of the host, not the target. That's a miscompilation. This example, while being simple, is also simple to fix. But it's an example of how it's not as trivial as "use the compiler to compile the program, then run it." Which maybe isn't how you think of this feature, but how I was, back before I knew anything about this topic :)

> I might be overreacting here though

Nah, I think that you're not wrong. It's just that, when you start applying this super rigorously, you end up in weird places. How can you trust any behavior in a language without a specification? How you can you trust a specification if that specification hasn't been formally proven? How you can trust an implementation of a formally proven specification? How you can you trust that the silicon you're running on does the right thing, even with your bug free, formally proven code?

Everyone chooses somewhere along this axis to be comfortable with. And everyone does something, including "I can ignore these problems because in practice they don't happen to me," to deal with the bits outside of what they consciously choose to focus on.


> An extremely simple example is cross compiling. In Rust, usize is dependent on the architecture you're compiling for. A very simple "just compile and run the program, get the answer, and use it" implementation of compile-time execution will produce a usize of the size of the host, not the target.

I get that there are non-obvious problems here, and as you say, this problem specifically has an easy fix, but I'd just like to note how Zig does this:

  const std = @import("std");
  pub fn main() anyerror!void {
      std.debug.warn("{}\n", .{.{
          @sizeOf(*usize),
          comptime @sizeOf(*usize)
      }});
  }
Modulo the `.{` weirdness, this probably looks familiar. By default, this prints out 8 and 8 on my system, but if I cross-compile to a 32-bit target, it prints 4 and 4.

> It's just that, when you start applying this super rigorously, you end up in weird places. How can you trust any behavior in a language without a specification?

I think this is a social issue for me; if rustc decides one day to change its behavior under my feet it feels like it's my fault for not having written proper Rust in the first place (even if the behavior wasn't properly defined in the first place), but if there's crazy things going on in the compiler due to bugs (that we didn't find, because proofs are hard), then that's not really my fault, in a sense. And of course, if my CPU decides to run my program wrong, that can't really be blamed on me. The end result in these three cases are all the same: the program didn't run as expected, but the blame (I don't want to point fingers, but this is the best word I could come up with) is different, and the probability of this happening is vastly different. I've never hit a CPU bug, but in the little unsafe Rust code I have written, I've had behavior change with a compiler update, which I'm sure is because I hit UB.

And for what it's worth, I would greatly prefer Rust having a proper spec, even if that would increase turnaround time for the language evolution, just to ensure that everyone really is on the same page with respect to what the language really should and shouldn't do. I realize that Rust would rather be careful and make sure that the decisions made are the right ones. I think it's a fair trade-off, but I'm not sure I would have made it, if it were up to me.


> I'd just like to note how Zig does this:

Right, what I'm talking about is the implementation of "comptime @sizeOf(*usize)".

That it does the right thing is good! It's easy to accidentally implement it in a way that does not.

> And for what it's worth, I would greatly prefer Rust having a proper spec

We all would :)


> It sound like people writing books without the rules on verb conjugation being really set.

I'm sure this happened earlier in the history of English. Of course, humans are much more forgiving than compilers.


Hehe yeah, it's not a great analogy :)


> Doing this well is not easy

Does this also apply to the in-language build system? Given both Rust and Zig's ergonomics, it just seems so brilliantly simple (at least in hindsight) to let the build system be a library. Is it just coincidence that I've only heard of this approach for zig and Jonathan Blow's language, or is there a technical reason this is more difficult than it seems?


> I've only heard of this approach for zig and Jonathan Blow's language

It's the same approach used by nix and guix. Nix is moderately successful. I'm typing this on a laptop running nixos :)

https://nixos.org/

https://guix.gnu.org/

If you're interested in this sort of thing, this is an excellent paper on build system design, although it focuses more on the properties of the build graph than on how the graph is constructed:

https://www.microsoft.com/en-us/research/uploads/prod/2018/0...


I don't know enough about Zig's build system, or Jai's, to be able to talk about their approach intelligently.


The reason it isn't done more often is that it's too much on the imperative side vs declarative builds.


> Is it just coincidence that I've only heard of this approach for zig and Jonathan Blow's language

It's also a feature in elixir (Mix). Interestingly elixir also has a comptime concept, so I think having comptime makes having a build library more sensible.


In case you didn't know, cargo is available as a library as well[0].

I don't know why the current Zig approach[1] would be preferable, as you dump some source code that you are now responsible to maintain in your project. Any bigger project project will require writing boilerplate code just to get things built.

It's also a bit of comparing apples to oranges, as Zig's build system doesn't come with a package manager (which I would say makes up a good chunk of Cargo's complexity).

[0]: https://crates.io/crates/cargo

[1]: https://ziglang.org/#Zig-Build-System




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: