[HN Gopher] Rust 1.62.0
___________________________________________________________________
Rust 1.62.0
Author : caution
Score : 194 points
Date : 2022-06-30 16:42 UTC (6 hours ago)
(HTM) web link (blog.rust-lang.org)
(TXT) w3m dump (blog.rust-lang.org)
| loeg wrote:
| derive(Default) for enums is cool, I like that.
| stunt wrote:
| Happy
|
| Compiler
|
| Happy
|
| Life
| monocasa wrote:
| Neat, although the blog post doesn't make this explicit, the new
| x86_64-unknown-none target disables the red zone, truly making it
| useful in kernels where otherwise an incoming interrupt would
| corrupt your stack.
| guthriej wrote:
| I hadn't heard of the red zone, this article explained it quite
| well: https://os.phil-opp.com/red-zone/.
| [deleted]
| nixpulvis wrote:
| Total ordering on floats! Does this mean we can sort &mut [f32]
| now!?
| [deleted]
| kibwen wrote:
| Yes, but note that it's not an implementation of the Ord trait,
| it's just a convenient opt-in comparison method. You would need
| to provide it as part of a custom sorting predicate, as shown
| in the documentation.
| [deleted]
| [deleted]
| Bromeo wrote:
| From the docstring for total_cmp
|
| `bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));`
|
| So yes, but you were already able to use `partial_cmp` before.
| kzrdude wrote:
| And if it's just floats, you can call it like
| `bois.sort_by(f64::total_cmp)`
| pavon wrote:
| Yeah, the difference is that total_cmp can handle NaNs,
| whereas with partial_cmp you either had to add your own
| handling, or get panics on NaN if you blindly call
| partial_cmp.unwrap().
|
| I think in most cases, splitting NaNs across the start and
| end of the list isn't desired behavior, so I'll probably keep
| using partial_cmp with my own handling.
| nixpulvis wrote:
| Does SQL define a default order/placement for NULLs in
| numeric (or otherwise) columns?
| tialaramex wrote:
| I think I'd be happier to see total_cmp anywhere that it's
| clear we want some consistent order and it's _not
| important_ what the order actually is.
|
| The hand-rolled solution risks inconsistency. Given the
| opportunity to pick the order, people _are_ going to pick
| different orders, sometimes by mistake, and providing
| total_cmp fixes that.
|
| I can see that in things which decided they should be Ord
| but internally have a f32 and so they need to implement the
| comparison themselves, total_cmp seems like it's almost
| always going to be the right choice for that unless
| partial_cmp with unwrap() is _definitely_ correct and they
| 're sure of it.
| jcranmer wrote:
| This is based on the IEEE 754 totalOrder predicate. If you
| look at how this function works on binary floats, it turns
| out that it sorts numbers as 0xffff, 0xfffe, 0xfffd, ...,
| 0x8001, 0x8000, 0x0000, 0x0001, 0x0002, ..., 0x7ffd,
| 0x7ffe, 0x7fff [1]. This is not a bad sort order, and the
| reason why the NaNs are split up are because of the
| existence of signed NaN.
|
| When it comes to floating point, it's probably better to
| bow to what IEEE 754 specifies (if it specifies something)
| than do what you come up yourself, even if it's less
| useful. x != x holding true for NaNs is another example
| here.
|
| [1] Actually, the sort order of NaN payloads is
| implementation-defined, but given the nice bit
| representation mentioned above is easy to implement, you're
| probably unlikely to see any other implementation.
| [deleted]
| tempusr wrote:
| The new cargo add feature is a great QoL update.
| ridiculous_fish wrote:
| Edit: Rust 1.62 uses futexes directly; ParkingLot is a thing but
| not backing mutex on Linux. Thanks to ibraheemdev for the
| correction.
|
| I'm working to understand how Rust 1.62 avoid allocations for
| futex-based locks. I think the summary is this:
|
| 1. A mutex is a u8. The mutex fast path is locking via atomic ops
| to set a bit.
|
| 2. Contention is resolved by adding the blocked thread into a
| wait queue. The queue is allocated/discovered via a global hash
| table, keyed by the address of the mutex. The mutex keeps a
| stable address while locked, as the lock holds shared ownership
| and so the mutex cannot be moved for the duration.
|
| I ported a POSIX semaphore wrapper from C++ to Rust, and needed
| an extra allocation for the same reason, to get an int with a
| stable address. Unfortunately this technique won't work for
| semaphores, they need to be async-signal safe. So I'm still stuck
| with `Pin<Box<UnsafeCell<sem_t>>>` where in C++ it's just `sem_t`
| and a deleted move constructor.
|
| Anyways this is a lot of hoops to jump through to avoid non-
| movable types, hope it's worth it!
| cwzwarich wrote:
| > 2. Contention is resolved by adding the blocked thread into a
| wait queue. The queue is allocated/discovered via a global hash
| table, keyed by the address of the mutex. The mutex keeps a
| stable address while locked, as the lock holds shared ownership
| and so the mutex cannot be moved for the duration.
|
| Wouldn't this break any platform-specific priority/importance
| donation mechanisms, or does Linux have a way to work around
| this?
| ridiculous_fish wrote:
| Actually upon reflection why wasn't this just trivial for
| futex? A Linux futex requires only user-space initialization,
| and it has a stable address while locked for the same reason,
| so you can get the same zero-allocations without the use of
| parking lot.
| ibraheemdev wrote:
| It uses the linux futex api directly, not a user space
| parking lot as used by the parking-lot crate.
| dthul wrote:
| It's very cool that mutexes on Linux don't require an allocation
| anymore! A very common pattern is to use an Arc<Mutex<T>> for
| sharing ownership across threads and as far as I can tell this
| will now only require one allocation instead of two.
| kzrdude wrote:
| And it's a stepping stone for things to come in the future -
| Rust 1.63 with compile time `Mutex::new`
| https://twitter.com/m_ou_se/status/1538209506085244929
| yakubin wrote:
| Once _std::thread::scope_ [1] is stabilised, in a lot of cases
| you're not going to need to wrap your Mutexes in Arcs anymore:
| #![feature(scoped_threads)] use std::thread; use
| std::sync::Mutex; fn main() { let a =
| Mutex::new(0u32); thread::scope(|s| {
| s.spawn(|| { *a.lock().unwrap() += 1;
| }); s.spawn(|| {
| *a.lock().unwrap() += 1; }); });
| assert_eq!(*a.lock().unwrap(), 2); }
|
| A nice glimpse of structured concurrency.
|
| [1]: <https://doc.rust-lang.org/std/thread/fn.scope.html>
|
| Edit: removed unnecessary "mut" from declaration of "a".
| dthul wrote:
| That's a great point! If you can guarantee that the threads
| don't outlive the Mutex an Arc is not even necessary.
| thedracle wrote:
| This is so beautiful.
|
| Super cool not having manual thread joining code.
| verdagon wrote:
| Very cool! I assume that anything captured will still need to
| have Sync/Send?
| yakubin wrote:
| Yes. The reason why currently you need to wrap Mutexes in
| Arcs is not thread-safety per se. Without
| _std::thread::scope_ the Rust compiler doesn 't know if the
| spawned threads won't outlive the Mutex (which is borrowed
| by the closures). So it's more about memory-safety than
| thread-safety in this case. _std::thread::scope_ guarantees
| that the threads will be joined in the _std::thread::scope_
| , thus providing enough information to the compiler (via
| lifetime annotations) for it to decide that they won't
| outlive the Mutex, so borrowing is safe in this case. That
| sorted, Mutex always had Sync and Send, so everything is in
| place to use it from multiple threads.
| bluejekyll wrote:
| Woh, I missed this (from that issue thread), "Merged and
| stabilized in 1.63!"
|
| Scoped threads are such a brilliant thing in the context of
| lifetimes.
| klabb3 wrote:
| It's only lexically scoped though, so you don't have much
| use of them in thread pools and, importantly, async
| runtimes.
|
| Pre-1.0, we used to have JoinHandle<'a> which let you use
| the borrow checker to its full potential with multiple
| threads. This is a big practical hurdle today, where
| mutices are required even for simple cases which don't
| suffer data races in practice.
| zwerdlds wrote:
| Not being too familiar with the underlying mechanics, I'm
| curious to know- How much will this improve the performance?
| loeg wrote:
| Minute -- you're often going to be better off eliminating the
| Arc/Mutex anyway. A (very) small but concrete win for some
| workloads.
| staticassertion wrote:
| > you're often going to be better off eliminating the
| Arc/Mutex anyway
|
| Not always. Mutexes can be really fast (10-20ns),
| especially since they often optimistically spin, and Arc in
| Rust is (often) _relatively_ low cost since you can hand
| out "free" refs without touching the atomic.
|
| If removing the Arc/Mutex would require allocations the
| Arc/Mutex could easily be faster.
| loeg wrote:
| > > often
|
| > Not always
|
| Yeah, that's what "often" means.
|
| > Mutexes can be really fast (10-20ns)
|
| Notably, still worse than 0 ns. Ditto for Arc's
| refcounting and additional allocation. I'm not saying go
| on a crusade against Arc+Mutex here, but the easiest way
| to make effective use of modern multicore CPUS is to go
| to shared-nothing, independent data-per-thread designs
| (obviating Arc+Mutex). And if you aren't using Arc+Mutex,
| it's harder to accidentally share mutable state between
| threads.
| staticassertion wrote:
| I just think people seriously overestimate the cost of a
| mutex when implemented efficiently. Unlocking a mutex can
| be ~10-20x faster than fetching a value from main memory,
| or just a bit slower than a few integer operations. The
| way people talk about mutex operations you'd think that
| it's akin to hitting disk when it's actually a few orders
| of magnitude closer to hitting your L2 cache.
| yakubin wrote:
| Don't atomic operations trigger cache synchronisation in
| CPUs? Doesn't that affect performance negatively? That
| would mean even a non-contended mutex would affect
| performance negatively. I suspect it depends a lot on the
| specific workload (and maybe even what addresses data is
| stored at in memory), so I'd measure the specific case,
| but that's my a priori gut feeling.
| staticassertion wrote:
| If there's no contention there's no more synchronization
| compared to any other cache lines afaik.
| loeg wrote:
| If it's non-contended, the mutex's cache line probably
| stays Exclusive in the local CPU and acquiring is pretty
| cheap.
| kzrdude wrote:
| I think the focus is on the synchronization and
| implementation choice based performance differences,
| https://twitter.com/m_ou_se/status/1526211117651050497 which
| are not super easy to characterize but come from much more
| than just removing an allocation.
| staticassertion wrote:
| https://twitter.com/m_ou_se/status/1526211117651050497
|
| These are synthetic benchmarks but it's quite significant in
| them.
|
| From a different tweet:
|
| > It's the total time for 32 threads each doing 10'000
| lock+unlocks (on a 64C/128T threadripper). So, the numbers
| you quoted correspond to a lock+unlock operation going from
| 8.75ns to 2.45ns, under low contention.
|
| > The numbers can vary a lot in different situations/hardware
| though.
| jstimpfle wrote:
| Depends on how you use it of course - how many mutexes do you
| need, etc... Likely you won't notice any difference.
| eventhorizonpl wrote:
| Rust is the language that makes me look forward to the next day
| at work.
| brundolf wrote:
| `cargo add` is such a small thing, but I'm so excited about it.
| Many tiny instances of friction as you have to open your browser
| and manually google a crate to find the latest version number so
| you can copy and paste it into your Cargo.toml
| pachico wrote:
| I can't really understand why I'm fluent in various languages but
| not Rust... I might have found my intellectual glass ceiling...
| adamdusty wrote:
| I learned c++ and rust around the same time. Even though c++
| was more difficult in every single aspect, I have used it over
| rust in every project since. Everything about rust was great.
| Pattern matching, enums, result types; I could go on forever,
| but I just can't get in "the zone" when I develop stuff in
| rust. I think the mental overhead is just too much for my brain
| to process. So I'm right there with you, rust is too smart for
| me.
| popcube wrote:
| usually explanation is, you should shoot your foot in c++ to
| understand why Rust is now design
| pizza234 wrote:
| Rust has a sort of meta aspect, in the sense of "programming
| the programming language", that other programming languages
| don't have. Each problem requires two solutions - the logical
| one and the programming language one.
|
| It takes time and effort to adjust... a lot of time and effort
| :)
|
| In my personal experience, there are two major hurdles.
|
| Access model is the first (I believe it's what is commonly
| referred to a "borrow checking"). It just happened one day that
| I was understanding the access model, and not screaming in
| terror anymore :) The same may happen to you, so don't feel
| incapable in the meanwhile.
|
| Lifetimes is the second hurdle, but even before fully
| understanding them, you'll be able to work on complex programs.
| Starlevel001 wrote:
| I can understand Rust when I'm writing my own code. But when it
| comes to understanding other people's code, it's essentially
| gibberish.
|
| A lot of library devs seem to have read "strong type system"
| and taken it as a challenge, meaning that half of their code is
| actually declarative to the compiler rather than readable in
| the source file. As a native Java dev this is very annoying.
| nu11ptr wrote:
| Rust can feel VERY intimidating at first, but honestly once you
| get over the steep but abruptly ending learning hump, writing
| Rust is no harder than any other language you are familiar
| with. I only started writing Rust last October, but felt very
| comfortable within a few months and now feel fairly proficient.
| As in all things, YMMV
| tmp_anon_22 wrote:
| Its a feature rich language with a more-complex syntax then
| many languages and a community that is still discovering its
| best practices, critical libraries, and more.
|
| Its a difficult language to learn full-stop. And its a language
| that can be used to produce valuable software, but probably
| should not be the first choice for many applications at most
| organizations.
| pkrumins wrote:
| Because it's not a programming language but a syntax error. It
| passes the duck test for a syntax error - it looks like a
| syntax error, it acts like a syntax error, and it prints a
| syntax error, so it is a syntax error. Avoid it!
| newaccount2021 wrote:
| try my approach
|
| - read as much learning material as possible
|
| - write some non-trivial learning code, possibly a project you
| already know
|
| - get a little frustrated, walk away
|
| ....wait three months
|
| - come back
|
| - re-read what you had done earlier
|
| - realize you actually knew quite a bit and you can now "learn
| from yourself"
|
| - make progress
| orangepurple wrote:
| This is the spacing effect in action
| https://en.wikipedia.org/wiki/Spacing_effect
| labrador wrote:
| The syntax is really off putting, but I suspect I'm not alone
| in that feeling, so someone will make a pretty Rust Front that
| transpiles to Rust. I'll wait.
| wwalexander wrote:
| Rust definitely has a different feeling of mastery than other
| languages, due to the fact that most if not all bugs are caught
| during the compilation phase.
|
| In other languages I like, I reach a point where I'm generally
| confident my code will compile before I ask it to. In Rust, for
| all but the most trivial logic, the compiler will usually have
| several things to say. However, I usually feel like the
| compiler is guiding me towards a simpler/more idiomatic/better
| way of doing things, and the compiler is more strict simply
| because Rust is so well-equipped for static compile-time
| analysis.
|
| So fret not, the borrow checker and all the other checks that
| happen when writing Rust exist _precisely because_ these things
| are so painful and complex to reason about as a human. The
| compiler is your colleague, not your boss!
| okwubodu wrote:
| I find Rust much easier to hold in my head as well. It's
| reduced the need for mid-session, "just-in-case" compilations
| to the point that building sometimes feels like a formality.
| eventhorizonpl wrote:
| "most if not all bugs"
|
| Unfortunatelly logic errors are not caught - this would
| require some sophisticated AI in compiler. But other problems
| should be caught.
|
| Of course Rust will not prevent you from placing backdoors
| and other more sophisticated vulnerabilities in code.
| Compiler is great, but you still have to think.
| yakubin wrote:
| Your comment was dead for some reason. I vouched for it,
| because I think it's interesting to discuss.
|
| Although obviously no compiler of a Turing-complete
| language is going to eliminate all logic errors, the user
| of a language like Rust or Haskell may use the type system
| to prevent certain classes of logical errors (not just
| problems with the shape of data, or incorrect memory
| handling). The way you do it is with Abstract Data Types.
| One example of such a type in Rust is _& str_. If you don't
| use unsafe code, it should preserve the invariant that the
| slice holds valid UTF-8 data. Containing invalid UTF-8 data
| would be a logical error, not a memory error or data shape
| error. Similar things may be achieved in C++ and Java with
| the use of access-modifiers (public vs private class fields
| and methods). The idea is well-explained in the famous
| _Parse, don 't validate_[1] article.
|
| The flipside is that too much of it and code becomes so
| complicated, it's very hard to work with --- you're falling
| into a Turing tarpit[2]. It becomes easier to just write
| simple code without bugs, without using all that type
| system wizardry. But a judicious use of this pattern, where
| it's appropriate, may be very beneficial.
|
| [1]: <https://lexi-lambda.github.io/blog/2019/11/05/parse-
| don-t-va...>
|
| [2]: <https://en.wikipedia.org/wiki/Turing_tarpit>
| nicoburns wrote:
| Are all the other languages fairly mainstream ones? Most
| procedural/OOP languages are similar enough that if you've
| learnt one you've basically learnt them all. Rust is a just a
| bit different and requires actually learning something new.
|
| For 90% of people I think the main hurdle is realising this.
| srvmshr wrote:
| What is the best way to pick up Rust and its best practices
| as of today? References welcome (thanks in advance!)
| pizza234 wrote:
| I think this (education) is a lacking area in Rust.
|
| You can read the reference book, and even a few other ones,
| but still not being able to have a sufficient/solid grasp
| of the language. I couldn't find good material past the
| beginner stage (I consider Rust for Rustaceans advanced).
|
| My personal advice is to find some project you'd like to
| implement, and practice a lot, or contribute to small
| projects you like, without worrying about best practices.
|
| There have been definitely many moments where I wanted to
| close the Rust chapter, and that's why I think it's more
| important than other languages to keep the motivation high,
| which I think is best achieved by working on projects.
|
| Rustlings is nice but... not stimulating.
| nu11ptr wrote:
| I found the O'reilly book, "Programming Rust" 2nd edition,
| to be the best book. It is long but thorough. "The book"
| might be a better starting point, but is less thorough I
| thought, and while it left me feeling more like "I got
| this", I didn't think it prepared me for "real world" Rust
| quite as well as the O'reilly book.
| ttfkam wrote:
| My advice is to avoid optimization like the plague while
| learning Rust. Don't worry about extra copying or
| optimizing lifetimes or any of it. Make all the "extra"
| structure and String copies.
|
| Doing it the "basic" way is sooooooo much easier, which is
| important while learning. Nine times out of ten it will be
| fast/efficient enough anyway.
|
| After you've got a handle on it with a few non-trivial
| programs under your belt, then start tightening up once you
| have the necessary context and familiarity.
| jgerrish wrote:
| This is fairly good advice, but I've run into a few cases
| where codebases don't "optimize lifetimes" and you're
| left with static lifetimes everywhere. Which is ok for
| some use cases, but it's a core language concept. One
| that is confusing unless you work with it some.
|
| While the Rust syntax around lifetimes can be confusing,
| The Rust Book does a decent guide describing what
| lifetimes are. Reading up on Modern C++ practices and
| language constructs actually helps with Rust too.
|
| The rustdoc book doesn't have a lot of examples of the
| full markdown support for documenting your code
| unfortunately. Browsing through std helps.
|
| Cargo rocks, and it's easy to spin up a new project. One
| thing I did was create a few new ones just for concepts
| that were difficult to me at first.
| ArchOversight wrote:
| The Rust Programming Language book is absolutely fantastic:
| https://doc.rust-lang.org/book/index.html
|
| It's a pretty quick read and gives you a good handle on
| Rust fairly quickly.
| olalonde wrote:
| https://github.com/rust-lang/rustlings
| [deleted]
| JCWasmx86 wrote:
| Have the same problem, I was able to pick up a lot of languages
| to fix programs and/or add features to an existing codebase,
| but rust was really frustrating. I programmed with it around 3
| months and I still need 10 times as long for implementing some
| things (And the async thing is really, really awkward)
| woodruffw wrote:
| If it helps, I was very discouraged during my first two
| attempts to learn Rust (both in early/mid 2018). I thought I
| had also reached my limit.
|
| If you haven't tried again in a while, you should give it
| another attempt -- I found it _much_ easier after the 2018
| edition was finalized, in part because of significant
| improvements to the borrow checker[1]. In terms of programming
| ergonomics, the pre-2018 and post-2018 versions of the language
| _feel_ very different, even if they happen to share most of the
| same syntax.
|
| [1]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-
| rust-201...
| pachico wrote:
| I'll definitely give it another try. Cheers
| verdagon wrote:
| I've seen people find Rust difficult for three reasons:
|
| * &mut is an "infectious leaky abstraction". It places
| restrictions on the caller, specifically that nobody can have a
| reference to that data. This disqualifies many useful patterns
| such as backreferences, observers, dependency references,
| graphs, delegates, and certain kinds of RAII.
|
| * Rust tends to lean very heavily on the type system to surface
| as much detail as possible into e.g. function signatures, but
| can conflict when the signature is set in stone, such as when
| implementing a trait or exposing a public function. It also
| does this with non-type-system denizens, such as async/await.
|
| * A reluctance to fall back to Rc and RefCell. Programs often
| have inherent shared mutability, and the alternatives are often
| more complex.
|
| These restrictions make the borrow checker incompatible with
| code we'd naturally write in any other language. Luckily, with
| enough practice, it can "click" and one can get used to the
| architectures that are compatible with its restrictions.
|
| The tradeoff isn't ideal for some use cases. For others, it can
| be a great fit.
| ArchOversight wrote:
| I used to feel like I was fluent in C++ but over time I
| realized that I was using just like 40-50% of the language
| because the rest of it was so complicated that it made it
| difficult to work with others who may not have had as deep of a
| knowledge.
|
| With Rust I've found that even though sometimes it feels like
| it is harder to write code with, I am finding it far more
| likely that it is correct when the compiler is happy with it,
| and I find myself worrying much less about move
| semantics/correctness/pointers and all that stuff like I was
| with C++, it has allowed me to move faster and not spend as
| much mental time on trying to make sure/understand if what I am
| doing is ACTUALLY safe.
|
| I am using C++ as an example, because the other language I use
| regularly is Python and there are still pieces of Python code
| that make me scratch my head with "how does THAT work?!"
| wwalexander wrote:
| Absolutely agree with you. Rust lets me offload all the
| boring, inscrutable memory management checking to the
| compiler. Sure, I can't get away with undefined behavior, but
| I spend my Rust programming time thinking about the business
| logic and letting the compiler tell me when the books are
| off.
| jcelerier wrote:
| > I am finding it far more likely that it is correct when the
| compiler is happy with it,
|
| it's pretty interesting though - surely you would have
| flagged the equivalent C++ code to what is discussed in
| https://github.com/rust-lang/rust/issues/93740, if my
| understanding is correct - akin to
| std::unique_ptr<pthread_mutex_t>, as obviously wrong ? It's a
| pattern that was apparently commonplace in rust until now yet
| I would definitely not let my first year comp. sci. interns
| get away with something like this during code review.
| tialaramex wrote:
| What about it is "obviously wrong" ? Did you mean here,
| "Not performing as well as I'd like" ?
| jjtheblunt wrote:
| does Rust have a concise manual, like docs.python.org or
| go.dev/pkg provide?
|
| Edit : thanks, all! very cool
| tialaramex wrote:
| Sort of. Rust's Standard Library documentation describes the
| entire language in perhaps the way you're thinking of
|
| https://doc.rust-lang.org/std/index.html
|
| e.g https://doc.rust-lang.org/std/keyword.as.html explains
| the 'as' keyword
|
| https://doc.rust-lang.org/std/primitive.i128.html documents
| the 128-bit signed integer type
|
| Or, maybe you are thinking purely a language document like:
|
| https://doc.rust-lang.org/reference/introduction.html
| stusmall wrote:
| While others are pointing you towards library docs I highly
| suggest going to the rust book[1] instead. A lot of languages
| you are fine learning breadth first by going through some
| documentation and playing around building things. This is how
| I learn best myself, but it doesn't work well with rust. It
| has enough unique concepts and concepts you might not have
| come across unless you have experience with a similar
| language. It is one language that is best served by a depth
| first approach. I usually suggest reading chapters 1-11
| before trying to dive in and build something.
|
| 1. https://doc.rust-lang.org/book/index.html
| nindalf wrote:
| https://doc.rust-lang.org/std/index.html has the
| documentation for the standard library.
|
| In addition https://docs.rs contains the documentation for
| all publicly available Rust code.
|
| The main tool used to generate these docs is very good and
| easy to use. As a result documentation is usually pretty
| good.
___________________________________________________________________
(page generated 2022-06-30 23:02 UTC)