Live data from Hacker News

The borrowchecker is what I like the least about Rust

viralinstruction.com

281–290 of 459 posts

Re: The borrowchecker is what I like the least about Rust

#281
post #58

Earlier quoted context omitted.

In C++, the signature of a function template doesn't necessarily tell you what types you can successfully call it with, nor what the return type is. Much analysis is delayed until all templates are instantiated, with famously terrible consequences for error messages, compile times, and tools like IDEs and linters. By contrast, rust's monomorphization achieves many of the same goals, but is less of a headache to use b…

> In C++, the signature of a function template doesn't necessarily tell you what types you can successfully call it with, nor what the return type is. That's the whole point of Concepts, though.

Concepts are basically a half solution - they check that a type has some set of properties, but they don't check that the implementation only uses those properties. As a result, even with concepts you can't know what types will work in a template without looking at the implementation as well.

Example [0]:

    #include 

    template
    concept fooable = requires(T t) {
        { t.foo() } -> std::same_as;
    };

    struct only_foo {
        int foo();
    };

    struct foo_and_bar {
        int foo();
        int bar();
    };

    template
    int do_foo_bar(T t) {
        t.bar(); // Compiles despite fooable not specifying the presence of bar()
        return t.foo();
    }

    // Succeeds despite fooable only requiring foo()
    template int do_foo_bar(foo_and_bar t);

    // Fails even though only_foo satisfies fooable
    template int do_foo_bar(only_foo t);
[0]: https://cpp.godbolt.org/z/jh6vMnajj

Re: The borrowchecker is what I like the least about Rust

#282

I don't use Rust much, but I agree with the thrust of the article. However, I do think that the borrowchecker is the only reason Rust actually caught on. In my opinion, it's really hard for a new language to succeed unless you can point to something and say "You literally can't do this in your language" Without something like that, I think it just would have been impossible for Rust to gain enough momentum, and also…

Agreed. As a comparison Golang was sold as "CSP like Erlang without the weird syntax" but people realized channels kind of suck and goroutines are not really a lot better than threads in other languages. The actual core of OTP was the supervisor tree but that's too complicated so Golang is basically just more concise Java. I don't think this is a bad thing but it's a funny consequence that to become mainstream you ha…

if err != nil every few lines is hardly "more concise"...

Re: The borrowchecker is what I like the least about Rust

#283
post #164

Earlier quoted context omitted.

Agreed. As a comparison Golang was sold as "CSP like Erlang without the weird syntax" but people realized channels kind of suck and goroutines are not really a lot better than threads in other languages. The actual core of OTP was the supervisor tree but that's too complicated so Golang is basically just more concise Java. I don't think this is a bad thing but it's a funny consequence that to become mainstream you ha…

> Golang is basically just more concise Java. That is exactly how it was sold. A safe C, or a nicer simpler Java. Nobody cared about Erlang back then and nobody does today. I write Erlang for a living.

> nicer simpler Java

Ironically, Java was sold as a "nicer simpler C++".

Re: The borrowchecker is what I like the least about Rust

#284

Earlier quoted context omitted.

Yikes, language flamebait in 2025?

Flamebait? It's literally what the designers of Golang said publicly about the background of prospective developers, and how that constrained the language design: "The key point here is our programmers are Googlers, they’re not researchers. They're typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They're not capable of understanding a brilliant lang…

Nowhere in this quote are these fresh grads equated to "lousy programmers", though (which the flamebaity comment did).

And interpreting the quote charitably I'm going to have to agree with it - I don't think many of my coworkers care enough to get to the point where they'd appreciate everything something like Haskell can do for them.

Re: The borrowchecker is what I like the least about Rust

#285
post #166

I don't use Rust much, but I agree with the thrust of the article. However, I do think that the borrowchecker is the only reason Rust actually caught on. In my opinion, it's really hard for a new language to succeed unless you can point to something and say "You literally can't do this in your language" Without something like that, I think it just would have been impossible for Rust to gain enough momentum, and also…

About 20 years ago your choice of language basically boiled down to what you were going to pick for your web server. Your choices were - Java (popular among people who went to college and learned all about OOP or places that had a lot of "enterprise" software development) - Ruby on Rails (which was the hot new thing) - Python or Perl to be the P in your LAMP stack - C++ for "performance" All of these were kitchen sin…

Not everybody is writing web applications. In fact, all of the languages have been invented years or even decades before the internet became popular. Except maybe for Perl, they have been designed as general purpose programming languages.

Re: The borrowchecker is what I like the least about Rust

#286
post #151

There are some artificial limitations, but I love the upside: I don't need defensive programming! When my function gets an exclusive reference to an object, I know for sure that it won't be touched by the caller while I use it, but I can still mutate it freely. I never need to make deep copies of inputs defensively just in case the caller tries to keep a reference to somewhere in the object they've passed to my funct…

Yes! One of the worst bugs to debug in my entire career boiled down to a piece of Java mutating a HashSet that it received from another component. That other component had independently made the decision to cache these HashSet instances. Boom! Spooky failure scenarios where requests only start to fail if you previously made an unrelated request that happened to mutate the cached object. This is an example where owner…

> This is an example where ownership semantics would have prevented that bug.

It’s also a bug prevented by basic good practices in Java. You can’t cache copies of mutable data and you can’t mutate shared data. Yes it’s a shame that Java won’t help you do that but I honestly never see mistakes like this except in code review for very junior developers.

Re: The borrowchecker is what I like the least about Rust

#287

I don't use Rust much, but I agree with the thrust of the article. However, I do think that the borrowchecker is the only reason Rust actually caught on. In my opinion, it's really hard for a new language to succeed unless you can point to something and say "You literally can't do this in your language" Without something like that, I think it just would have been impossible for Rust to gain enough momentum, and also…

> but I'm not going to switch because I can technically do all that stuff in C++"

That's exactly what people say about Rust: just get good, use some tools, and be careful - and you can achieve the same memory safety.

Re: The borrowchecker is what I like the least about Rust

#288
The point about inter-procedural borrow checking is fair -- and in fact not a matter of "sufficiently smart" borrow checker, but a rather fundamental type system limitation. But the flaw here is pretty manageable -- sometimes you can get away with calling .split_at_mut(...), sometimes you can borrow the field directly instead of going through a wrapper method, sometimes you have to be mindful to provide a split_at_mut equivalent yourself. Last I checked there was some work being done on "partial borrows", which could solve this.

Most of the other criticisms are pretty disappointing, though.

> The following example is a famous illustration of how it can't properly reason across branches, either:

Except that function body would have been better rewritten as map.entry(key).or_default() -- which passes the borrow checker just fine and is more performant as it avoids multiple lookups. I suspect many other examples would benefit from being re-written into higher-level primitives that can be easier to borrow-check in this manner.

> But what's the point of the rules in this case, though? Here, the ownership rules does not prevent use after free, or double free, or data races, or any other bug. It's perfectly clear to a human that this code is fine and doesn't have any actual ownership issues.

What if Id represents a file descriptor that ought to be closed when the value ceases to exist? Or some other type of handle? This is an ownership problem: these are not limited to memory safety issues. For very good API stability reasons, without an explicit #[derive(Clone,Copy)] the compiler is not free to assume the type represents pure information that can be copied at will, but can only treat it as one potentially containing owned resources, that just happens not to include any at this time.

> References to temporary values, e.g. values created in a closure, are forbidden even though it's obvious to a human that the solution is simply to extend the lifetime of the value to its use outside the closure.

Which is to say, to what? The type signature does not say whether a closure will be called immediately or in another thread after two hours. And in which stack frame should the value be stored, the soon-to-be-exiting closure's?

Re: The borrowchecker is what I like the least about Rust

#290
post #286

Earlier quoted context omitted.

Yes! One of the worst bugs to debug in my entire career boiled down to a piece of Java mutating a HashSet that it received from another component. That other component had independently made the decision to cache these HashSet instances. Boom! Spooky failure scenarios where requests only start to fail if you previously made an unrelated request that happened to mutate the cached object. This is an example where owner…

> This is an example where ownership semantics would have prevented that bug. It’s also a bug prevented by basic good practices in Java. You can’t cache copies of mutable data and you can’t mutate shared data. Yes it’s a shame that Java won’t help you do that but I honestly never see mistakes like this except in code review for very junior developers.

The whole point is that languages like Java won't keep track of what's "shared" or "mutable" for you. And no, it doesn't just trip up "very junior developers in code review", quite the opposite. It typically comes up as surprising cross-module interactions in evolving code bases, that no "code review" process can feasibly catch.
Post reply on HN