Live data from Hacker News

My favorite Rust function

blog.jabid.in

71–80 of 197 posts

Re: My favorite Rust function

#71
I get the feeling this doesn't really get into the meat of what "drop" is. It seems you can't really explain why you "love" a function without discussing its purpose. Maybe I'm wrong, I'm only really an outsider looking in when it comes to rust, but it does fascinate me as far as its goals. I would go so far as to say that it will be important for systems programmers to know in the not too distant future (if it's not already).

Isn't it really only there in case someone needs to "hook into" the drop functionality before the variable is dropped? Please correct me if I'm wrong.

EDIT: Minor editing to clarify meaning.

Re: My favorite Rust function

#72
post #62

For me, rust is still love & hate, even after 1 year of half-time (most of the free time I have) hacking. It's a wonderful language but there are still some PITAs. For example you can't initialize some const x: SomeStruct with a function call. Also, zero-cost abstraction is likely the biggest bullshit I've ever heard, there is a lot of cost and there's also a lot of waiting for compiler if you're using cargo packages…

> Also, zero-cost abstraction is likely the biggest bullshit I've ever heard, there is a lot of cost and there's also a lot of waiting for compiler if you're using cargo packages. While someone else is right that "zero-cost" refers to runtime cost rather than compilation cost, dependencies are the biggest problem. The program `spotifyd` takes over an hour to compile on my X200 laptop. This is, for reference, the same…

An X200 is also an ancient machine. Do you value your own time so little? Clearly you are annoyed by the compile times?

You can get a $200 CPU that will blast through a kernel compile in 3 minutes.

Re: My favorite Rust function

#74
post #62

For me, rust is still love & hate, even after 1 year of half-time (most of the free time I have) hacking. It's a wonderful language but there are still some PITAs. For example you can't initialize some const x: SomeStruct with a function call. Also, zero-cost abstraction is likely the biggest bullshit I've ever heard, there is a lot of cost and there's also a lot of waiting for compiler if you're using cargo packages…

> Also, zero-cost abstraction is likely the biggest bullshit I've ever heard, there is a lot of cost and there's also a lot of waiting for compiler if you're using cargo packages. While someone else is right that "zero-cost" refers to runtime cost rather than compilation cost, dependencies are the biggest problem. The program `spotifyd` takes over an hour to compile on my X200 laptop. This is, for reference, the same…

I've also heard that Rust compilation is slow, so I put off learning it for a while. I finally dug in deep recently and, to be honest, I don't understand the issue. Rust compilation is quite fast in my experience.

Your comment was the first I've heard of spotifyd, so I downloaded it from github and ran "cargo build". I spent 3 minutes figuring out that I needed to install the "libasound2-dev" package, then I spent less than 2 minutes compiling. I watched the clock to be sure, but after only 2 minutes, Cargo produced a target/debug/spotifyd executable. Maybe you're referring to --release compilation?

I don't have the fastest PC, it's just an 8 year old desktop with a 6 core Intel i7 980x running Ubuntu 18.04. Rust compilation maxes out all the cores, which is really nice.

With the RustEnhanced package added to Sublime Text, editing Rust code is a very interactive experience with practically instant feedback. Running tests is fast too.

I wish I understood why some people are apparently having a very different experience. Maybe it's slow on some operating systems.

Re: My favorite Rust function

#75
post #25

Do variables go out of scope after last use or when the function exits? I could see the former evolving into the language if it’s not already the default behavior. In which case there’s only one situation where I could see this useful, and that’s when you are building a large object to replace an old one. The semantics of foo = buildGiantBoject(); In most languages is that foo exists until reassigned. When the object…

Variables go "out of scope" (in at least one sense) at last use, but are not `Drop`-ed (de-allocated, etc...) until the end of the function. The difference is important because of rust's rule against simultaneous aliasing and mutability. Consider this example:

  fn main() {
    let mut a = 1;
    let b = &mut a;
    *b = 2;
    println!("{}", a); // prints "2"
    // *b = 4; // If this line is uncommented, compile time error.
  }
Because b is a mutable reference to a, this means that a cannot be accessed directly until b goes out of scope. In this sense, b goes out of scope the last time it's used. _However_, AFAIK, b isn't actually de-allocated until the end of the function.

Of course, it doesn't matter in this trivial case, because b is just some bytes in the current stack frame so there's nothing to actually de-allocate. But if b were a complex type that _also_ had some memory to de-allocate, this wouldn't happen until the end of main(). But in this case, b's scope also lasts until the end of main, which is kind of like adding that last line back in...

This can be seen in the following example, where b has an explicit type:

  struct B(&'a mut i32);
  impl Drop for B {
    fn drop(&mut self) {
      // We'd still have a mutable reference to a here...
      // If B owned resources and needed to free them, this is where that would happen
    }
  }
  fn main() {
    let mut a = 1;
    let b = B(&mut a);
    *b.0 = 2;
    std::mem::drop(b); // Comment this line out, get compiler error
    println!("{}", a); // prints "2"
  }

In this example, without the std::mem::drop() line, the implementation for Drop (i.e., B's destructor), B::drop would be implicitly called at the end of the function. But in that case, B::drop() would still have a mutable reference to a, which makes the println call produce a "cannot borrow `a` as immutable because it is also borrowed as mutable" compile time error.

In other words, this "going out of scope at last use" is really about rust's lifetimes system, not memory allocation.

IMHO... this is one of the rough edges in rust's somewhat steep learning curve. Rust's lifetimes rules make the language kind of complicated, though getting memory safety in a systems programming language is worth the trade-off. There's a lot of syntactic sugar that makes things a LOT easier and less verbose in most cases, but the learning curve trade-off for _that_ is that, when you _do_ run into the more complex cases that the compiler can't figure out for you, it's easy to get lost, because there are a few extra puzzle pieces to fit together. Still way better than the foot-gun that is C, though. At least for me... YMMV, obviously.

Re: My favorite Rust function

#76
post #66

Earlier quoted context omitted.

Your comment is weird. The one making you deal with the little details should be rust, e.g go is garbage collected. Secondly, javascript + type annotations is typescript.

Disclaimer: I’ve never tried to write Go. Memory management is not the only type of “little detail.” For instance, rust provides common collection operations (filer, map, find…) in the standard library. In go (AFIAK), you need to hand-write a loop for each. IMO, the rust version is takes much less mental bandwidth to write and understand.

rust provides common collection operations (filer, map, find…) Those are just standard functional methods available in most languages. Go indeed is noteworthy for it's lack of features.

Re: My favorite Rust function

#77
post #64

Earlier quoted context omitted.

Another PITA is the lack of safe static variables.

Rust does have safe static variables. You just need a) to use interior mutability (`static mut` is a very strange feature that should probably never have existed) and b) to ensure that its type is `Sync` (since multiple threads can obtain references to it). For example, use an atomic integer: https://play.rust-lang.org/?version=stable&mode=debug&editio... You can also use types built on std::sync::Once and UnsafeCell…

Interesting but this seems so unergonomic that I will still be virtually forced to not use static variables and thus loose their expressive power.

Re: My favorite Rust function

#78

I get the feeling this doesn't really get into the meat of what "drop" is. It seems you can't really explain why you "love" a function without discussing its purpose. Maybe I'm wrong, I'm only really an outsider looking in when it comes to rust, but it does fascinate me as far as its goals. I would go so far as to say that it will be important for systems programmers to know in the not too distant future (if it's not…

Yes, to do anything interesting, you need to implement the Drop trait, which causes interesting behavior to happen here.

Re: My favorite Rust function

#79

I get the feeling this doesn't really get into the meat of what "drop" is. It seems you can't really explain why you "love" a function without discussing its purpose. Maybe I'm wrong, I'm only really an outsider looking in when it comes to rust, but it does fascinate me as far as its goals. I would go so far as to say that it will be important for systems programmers to know in the not too distant future (if it's not…

Yes, to do anything interesting, you need to implement the Drop trait, which causes interesting behavior to happen here.

An example of the implementation is all that's missing from the blog post.

Re: My favorite Rust function

#80
post #41

Earlier quoted context omitted.

It used to, they got subtler. See https://stackoverflow.com/questions/50251487/what-are-non-le...

NLL does not change those semantics; drop still runs at the end of the scope. It counts as a "use" for the purposes of NLL and thus keeps values with destructors alive.

For some history, it was talked about changing this, but we couldn’t, due to back compatibility and it wasn’t clear it was actually a good idea. This was called “wary drop”.
Post reply on HN