Live data from Hacker News

Common Rust Lifetime Misconceptions (2020)

github.com

61–70 of 89 posts

Re: Common Rust Lifetime Misconceptions (2020)

#61

Earlier quoted context omitted.

Wouldn't fixing 10 just mean allowing things that were previously not allowed? That's not a breaking change. What am I missing?

No it will not: fn requires_static(_: &'static str) {} let long_lifetime: &'static str = ""; let closure = |_input: &str| -> &str { long_lifetime }; let short_lifetime = &String::new(); requires_static(closure(short_lifetime)); This code compiles currently as the returned `&str` is inferred to be `&'static str` because this is what it actually returns, but with #10 fixed it will not because lifetime elision rules say…

Hm, in this case it's actually nice that this works because there's nothing unsafe or unexpected going on.

Re: Common Rust Lifetime Misconceptions (2020)

#62

Earlier quoted context omitted.

The overhead of an uncontested lock is not much more than a memory operation but it allows you to be able to use the same code in threaded context in tokio async which is a huge benefit. Unless you need the optimization (i.e. you profiled and determined that Arc in a hot loop is slowing you down) I think it's fine to use Arc in general.

> The overhead of an uncontested lock is not much more than a memory operation An atomic memory operation! These can be orders of magnitude slower than regular memory operations.

An atomic read-modify-write. Atomic non-seq-cst load/stores can be cheap.

/Overly pedantic

Re: Common Rust Lifetime Misconceptions (2020)

#63

Earlier quoted context omitted.

Good advice, though I'd recommend Rc > instead of Arc > if you're not sharing the data between threads, to avoid synchronization overhead. I use Arc pretty rarely.

tokio is so wide spread now such that Arc > is coincidentally the right choice. I'm not saying that's a good thing.

Doesn't tokio have a single-threaded runtime where that's not needed?

Re: Common Rust Lifetime Misconceptions (2020)

#64
post #60

I just clone everywhere and write Rust like a high level language. Then, once I need to optimize more, if I ever do (as Rust is many times faster than other languages even with liberal cloning), then I simply go through and remove the clone where needed.

> as Rust is many times faster than other languages even with liberal cloning Have you really compared? I have. Rust was faster for "small input", but quickly got beaten by Java and other languages I tried because the cost of doing things this way grows exponentially. I suggest you run benchmarks before you make your mind up and start throwing opinions around.

I have never benchmarked Java vs other languages, but from experience java applications always have horrible startup time. So, there might be some contexts in which long running Java application can beat Rust or other language, but if you need something that starts instantly (like CLI utilities) Java is a no-go.

Another wart is that there are some written and non-written standards on CLI arguments (e.g. long option names should start with double hyphens) that 99% of Java CLI apps violate for some reason. Maybe I'm a perfectionist but it makes me uncomfortable to use Java CLI apps.

Re: Common Rust Lifetime Misconceptions (2020)

#65

How I bail myself out of Rust lifetime problems as somebody who probably learned Rust the wrong way (by just trying to build stuff as if it were C/node.js and run into problems instead of slowing down + reading): 1. .clone() / .to_owned() 1. String -> vs &String/&str with & borrow 1. lazy_static / OnceCell + Lazy / OnceLock 1. Arc > with lots of .lock(). What would start off as like NULL in Java/C is Arc >> and you h…

Cloning things which are Copy (such as u32) is futile and Clippy will tell you not to bother where it can see this is definitely Copy. If you don't use Clippy, I'd suggest trying it for a while.

Rc will be faster (if that matters to you) than Arc but it can't cross threads. (Safe) Rust will check you didn't get this wrong, so there's no danger but obviously knowing ahead of time avoids writing an Rc that you then need to be an Arc instead.

Sometimes it's tidier to write the borrow in the type of a pattern match e.g. if let Some(&foo) = ... Means you won't need to dereference foo inside the block.

Re: Common Rust Lifetime Misconceptions (2020)

#66

Earlier quoted context omitted.

> The overhead of an uncontested lock is not much more than a memory operation An atomic memory operation! These can be orders of magnitude slower than regular memory operations.

An atomic read-modify-write . Atomic non-seq-cst load/stores can be cheap. /Overly pedantic

> An atomic read-modify-write.

No, this also applies to (non-relaxed) atomic loads and stores, depending on the platform.

> Atomic non-seq-cst load/stores can be cheap.

Relaxed atomic loads and stores are always cheap, but anything above requires additional memory order instructions on many platforms, most notably on ARM.

Here we are talking specifically about mutexes, which follow acquire release semantics.

To be clear: locking an uncontented mutex is indeed much, much cheaper than an actual call into the kernel, but it is not free either.

Re: Common Rust Lifetime Misconceptions (2020)

#67

Earlier quoted context omitted.

An atomic read-modify-write . Atomic non-seq-cst load/stores can be cheap. /Overly pedantic

> An atomic read-modify-write. No, this also applies to (non-relaxed) atomic loads and stores, depending on the platform. > Atomic non-seq-cst load/stores can be cheap. Relaxed atomic loads and stores are always cheap, but anything above requires additional memory order instructions on many platforms, most notably on ARM. Here we are talking specifically about mutexes, which follow acquire release semantics. To be cl…

Ok, technically we both used the weasel word 'can' so we are both right.

But even on ARM, these days store releases and load acquires, while not as free as on x86 are very cheap.

To make my statement more precise, typically what is still expensive pretty much everywhere is anything with #StoreLoad barrier semantics, which is what you need to acquire a mutex.

Re: Common Rust Lifetime Misconceptions (2020)

#69
post #60

Earlier quoted context omitted.

> as Rust is many times faster than other languages even with liberal cloning Have you really compared? I have. Rust was faster for "small input", but quickly got beaten by Java and other languages I tried because the cost of doing things this way grows exponentially. I suggest you run benchmarks before you make your mind up and start throwing opinions around.

I have never benchmarked Java vs other languages, but from experience java applications always have horrible startup time. So, there might be some contexts in which long running Java application can beat Rust or other language, but if you need something that starts instantly (like CLI utilities) Java is a no-go. Another wart is that there are some written and non-written standards on CLI arguments (e.g. long option n…

I'm no Java expert but they seem to be solving startup time with ahead-of-time (AOT) compilation.

https://medium.com/@subhajitc77/how-java-17-and-spring-boot-...

Re: Common Rust Lifetime Misconceptions (2020)

#70

Earlier quoted context omitted.

Me too. I also do this with .unwrap() - when I'm pretty sure of the happy path - while I'm prototyping. It's pretty easy afterwards to run back through and replace .unwrap() calls with better error handling. But as I improve, I'm getting more in the habit of using matching directly. Understanding lifetimes is probably really helpful for understanding library errors though and I need to go deeper there for sure

This is what I love about Rust, and other languages with these kinds of constructs. You have to acknowledge that something might e.g. fail. You can choose to do "nothing" (e.g. unwrap), but it must be done explicitly, which makes the ignored cases simple to identify later

I used to use OCaml before using Rust, it was similarly great and it's where Rust got the notion of the Option and Result types.
Post reply on HN