Hacker Newsnew | past | comments | ask | show | jobs | submit | newpavlov's commentslogin

For a system programming language the right solution is to properly track aliasing information in the type system as done in Rust.

Aliasing issues is just yet another instance of C/C++ inferiority holding the industry back. C could've learnt from Fortran, but we ended up with the language we have...


For systems programming the correct way is to have explicit annotations so you can tell the compiler things like:

    void foo(void *a, void *b, int n) {
        assume_aligned(a, 16);
        assume_stride(a, 16);
        assume_distinct(a, b);
        ... go and vectorize!
    }


LOL, nope. Those annotations must be part of the type system (e.g. `&mut T` in Rust) and must be checked by the compiler (the borrow checker). The language can provide escape hatches like `unsafe`, but they should be rarely used. Without it you get a fragile footgunny mess.

Just look at the utter failure of `restrict`. It was so rarely used in C that it took several years of constant nagging from Rust developers to iron out various bugs in compilers caused by it.


Does make me wonder what restrict-related bugs will be (have been?) uncovered in GCC, if any. Or whether the GCC devs saw what LLVM went through and decided to try to address any issues preemptively.


IIRC at least one of the `restrict` bugs found by Rust was reproduced on both LLVM and GCC.


gcc has had restrict for 25 years I think. I would hope most bugs have been squashed by now.


Possibly? LLVM had been around for a while as well but Rust still ended up running into aliasing-related optimizer bugs.

Now that I think about it some more, perhaps gfortran might be a differentiating factor? Not familiar enough with Fortran to guess as to how much it would exercise aliasing-related optimizations, though.


I think Fortran function arguments are assumed not to alias. I'm not sure if it matches C restrict semantics though.


Yeah, that's why I was wondering whether GCC might have shaken out its aliasing bugs. Sibling seems to recall otherwise, though.


I generally agree with this opinion and would love to see a proper well documented low-level API for working with GPU. But it would probably result in different "GPU ISAs" for different vendors and maybe even for different GPU generations from one vendor. The bloated firmwares and drivers operating on a higher abstraction level allow to hide a lot of internal implementation details from end users.

In such world most of software would still probably use something like Vulkan/DX/WebGPU to abstract over such ISAs, like we use today Java/JavaScript/Python to "abstract" over CPU ISA. And we also likely to have an NVIDIA monopoly similar to x86.


There’s a simple (but radical) solution that would force GPU vendors to settle on a common, stable ISA: forbid hardware vendors to distribute software. In practice, stop at the border hardware that comes from vendors who still distribute software.

That simple. Now to sell a GPU, the only way is to make an ISA so simple even third parties can make good drivers for it. And the first successful ISA will then force everyone else to implement the same ISA, so the same drivers will work for everyone.

Oh, one other thing that has to go away: patents must no longer apply to ISAs. That way, anyone who wants to make and sell x86, ARM, or whatever GPU ISA that emerges, legally can. No more discussion about which instruction set is open or not, they all just are.

Not that the US would ever want to submit Intel to such a brutal competition.


I wouldn't be so sure, as if we analogize to x86(_64), the ISA is stable and used by many vendors, but the underlying microarchitecture and caching model, etc., are free reign for impl-specific work.


For all my skepticism towards using LLM in programming (I think that the current trajectory leads to slow degradation of the IT industry and massive loss of expertise in the following decades), LLM-based advanced proof assistants is the only bright spot for which I have high hopes.

Generation of proofs requires a lot of complex pattern matching, so it's a very good fit for LLMs (assuming sufficiently big datasets are available). And we can automatically verify LLM output, so hallucinations are not the problem. You still need proper engineers to construct and understand specifications (with or without LLM help), but it can significantly reduce development cost of high assurance software. LLMs also could help with explaining why a proof can not be generated.

But I think it would require a Rust-like breakthrough, not in the sense of developing the fundamental technology (after all, Rust is fairly conservative from the PLT point of view), but in the sense of making it accessible for a wider audience of programmers.

I also hope that we will get LLM-guided compilers which generate equivalency proofs as part of the compilation process. Personally, I find it surprising that the industry is able to function as well as it does on top of software like LLVM which feels like a giant with feet of clay with its numerous miscompilation bugs and human-written optimization heuristics which are applied to a somewhat vague abstract machine model. Just look how long it took to fix the god damn noalias atrtibute! If not for Rust, it probably would've still been a bug ridden mess.


>we had about an inch of separation between our laser diodes and our photodiodes

Why can't you place them further away from each other using an additional optical system (i.e. a mirror) and adjusting for the additional distance in software?


You can, but customers like compact self-contained units. All trade offs.

Edit: There's basically three approaches to this problem that I'm aware of. Number one is to push the cross-talk below the noise floor -- your suggestion helps with this. Number two is to do noise cancellation by measuring your cross-talk and deleting it from the signal. Number three is to make the cross-talk signal distinct from a real reflection (e.g. by modulating the pulses so that there's low correlation between an in-flight pulse and a being-fired pulse). In practice, all three work nicely together; getting the cross-talk noise below saturation allows cancellation to leave the signal in place, and reduced correlation means that the imperfections of the cancellation still get cleaned up later in the pipeline.


In my (Rust-colored) opinion, the async keyword has two main problems:

1) It tracks code property which is usually omitted in sync code (i.e. most languages do not mark functions with "does IO"). Why IO is more important than "may panic", "uses bounded stack", "may perform allocations", etc.?

2) It implements an ad-hoc problem-specific effect system with various warts. And working around those warts requires re-implementation of half of the language.


> Why IO is more important than "may panic", "uses bounded stack", "may perform allocations", etc.?

Rust could use these markers as well.


I agree. But it should be done with a proper effect system, not a pile of ad hoc hacks built on abuse of the type system.


`async` is in the type system. In your mind, how would you mark and bubble up panicky functions, etc.? What would that look like?

I felt like a `panic` label for functions would be nice, but if we start stacking labels it becomes cumbersome:

  pub async panic alloc fn foo() {}
That feels dense.

I think ideally it would be something readers could spot at first glance, not something inferred.


>`async` is in the type system.

No, it's not. `async` is just syntax sugar, the "effect" gets emulated in the type system using `Future`. This is one of the reasons why the `async` system feels so foreign and requires so many language changes to make it remotely usable. `const` is much closer to a "true" effect (well, to be precise it's an anti-effect, but it's not important right now).

Also, I think it's useful to distinguish between effect and type systems, instead of lumping them into just "type system". The former applies to code and the latter to data.

>That feels dense.

Yes. But why `async` is more important than `alloc`? For some applications it's as important to know about potential allocations, as for other applications to know about whether code potentially yields or not.

Explicitly listing all effects would the most straightforward approach, but I think a more practical approach would be to have a list of "default effects", which can be overwritten on the crate (or maybe even module) level. And on the function level you will be able to opt-in or opt-out from effects if needed.

>I think ideally it would be something readers could spot at first glance

Well, you either can have "dense" or explicit "at first glance" signatures.


While I agree that dependency tree size can be sometimes a problem in Rust, I think it often gets overblown. Sure, having hundreds of dependencies in a "simple" project can be scary, but:

1) No one forces you to use dependencies with large number of transitive dependencies. For example, feel free to use `ureq` instead of `reqwest` pulling the async kitchen sink with it. If you see an unnecessary dependency, you could also ask maintainers to potentially remove it.

2) Are you sure that your project is as simple as you think?

3) What matters is not number of dependencies, but number of groups who maintain them.

On the last point, if your dependency tree has 20 dependencies maintained by the Rust lang team (such as `serde` or `libc`), your supply chain risks are not multiplied by 20, they stay at one and almost the same as using just `std`.


On your last note, I wish they would get on that signed crate subset. Having the same dependency tree as cargo, clippy, and rustc isn't increasing my risk.

Rust has already had a supply chain attack propagating via build.rs some years ago. It was noticed quickly, so staying pinned to the oldest thing that worked and had no cve pop in cargo audit is a decent strategy. The remaining risk is that some more niche dependency you use is and always has been compromised.


Is serde maintained by the Rust team? I thought it was basically a one-man show owned by dtolnay


Great comment! I agree about comptime, as a Rust programmer I consider it one of the areas where Zig is clearly better than Rust with its two macro systems and the declarative generics language. It's probably the biggest "killer feature" of the language.


> as a Rust programmer I consider it one of the areas where Zig is clearly better than Rust with its two macro systems and the declarative generics language

IMHO "clearly better" might be a matter of perspective; my impression is that this is one of those things where the different approaches buy you different tradeoffs. For example, by my understanding Rust's generics allows generic functions to be completely typechecked in isolation at the definition site, whereas Zig's comptime is more like C++ templates in that type checking can only be completed upon instantiation. I believe the capabilities of Rust's macros aren't quite the same as those for Zig's comptime - Rust's macros operate on syntax, so they can pull off transformations (e.g., #[derive], completely different syntax, etc.) that Zig's comptime can't (though that's not to say that Zig doesn't have its own solutions).

Of course, different people can and will disagree on which tradeoff is more worth it. There's certainly appeal on both sides here.


Consider that Python + C++ has proved to be a very strong combo: driver in Python, heavy lifting in C++.

It's possible that something similar might be the right path for metaprogramming. Rust's generics are simple and weaker than Zig's comptime, while proc macros are complicated and stronger than Zig's comptime.

So I think the jury's still out on whether Rust's metaprogramming is "better" than Zig's.


>often more performant than Rust with lower resource usage

[citation needed]

If we are to trust this page [0] Rust beats Zig on most benchmarks. In the Techempower benchmarks [1] Rust submissions dominate the TOP, while Zig is... quite far.

Several posts which I've seen in the past about Zig beating Rust by 3x or such all turned to be based on low quality Rust code with some performance pitfalls like measuring performance of writing into stdout (which Rust locks by default and Zig does not) or iterating over ..= ranges which are known to be problematic from the performance perspective.

[0]: https://programming-language-benchmarks.vercel.app/rust-vs-z...

[1]: https://www.techempower.com/benchmarks/


I would say in most submission-based benchmarks among languages that should perform similar, this mostly reflects the size and enthusiasm of the community.


Have you tried the GNU toolchain? IIRC rustup provides the option to use it instead of the MSVC toolchain during the initial installation.


I agree. In my opinion NaNs were a big mistake in the IEEE 754 spec. Not only they introduce a lot of special casing, but also consume a relatively big chunk of all values in 32 bit floats (~0.4%).

I am not saying we do not need NaNs (I would even love to see them in integers, see: https://news.ycombinator.com/item?id=45174074), but I would prefer if we had less of them in floats with clear sorting rules.


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

Search: