Hacker News new | ask | show | jobs
by deathanatos 4030 days ago
>> Nim also allows passing by non-const reference without any indication of such at the call site.

> Why is this a problem?

I have no experience with Nim. In C++, I've heard people argue that this is poor language design because at the call site, you cannot see that the variable is potentially being mutated; making it explicit that a mutable reference is being passed allows the reader of the call site to understand what mutations might occur without needing to know the signature of every function involved.

I've been learning Rust, which requires notation at the call site that you're passing a mutable reference, and thus far, I quite prefer it; I had been concerned that it might be "too much typing", but it's proven to be rare and unobtrusive.

1 comments

> I've been learning Rust, which requires notation at the call site that you're passing a mutable reference, and thus far, I quite prefer it; I had been concerned that it might be "too much typing", but it's proven to be rare and unobtrusive.

I'm so glad Rust made this design choice, because it means that a programmer can see very quickly where borrows are happening and understand where and where not new borrows could be inserted.

Take this example:

    struct Widget {
        name: String
    }
    
    fn jabberwock_the_widget(w: &mut Widget) {
        w.name.push_str(" (modified)");
    }
    
    fn main() {
        let jimbo = Widget { 
            name: "Jimbo".to_string() 
        };
        let name = &jimbo.name;
        jabberwock_the_widget(&mut jimbo);
    }
If that call were just `jabberwock_the_widget(jimbo)`, and I didn't have `jabberwock_the_widget`'s signature at hand, I would have to run the code through a compiler to see that there is an illegal mutable borrow on jimbo. With mutable borrows written so explicitly, it's clear at the call site that it can't happen with the existing borrow on the widget's name.
This has pretty limited scope, though. If a function you call returns an &mut you have no way to tell thanks to type inference, and when you use that value it looks like you're passing by-value.

Similarly if you call a method, there's no indication at all how `self` is being passed.

  > If a function you call returns an &mut you have no way 
  > to tell
Indeed, but also consider that a function can't return a `&mut` unless a `&mut` was passed in to it somehow. This means that the only way to implicitly introduce a `&mut` is via a method call like `foo.bar()` that takes `&mut self`, but also consider that it would be impossible to call the method here unless `foo` were explicitly declared as mutable to begin with. Given that mutable variables in Rust are relatively rare, these factors conspire to broadcast any mutable references quite clearly.