My 2020 Rust wish list

Hello. This year I tried writing something for the blog post call https://blog.dend.ro/my-rust-2020-wishlist/, although most things in there have been discussed before, especially the more technical points. Also, please forgive any awkward writing, inaccuracies or mistakes, it was a bit rushed.

Also on Reddit; I hope cross-posting is not an issue.

11 Likes

Wow, that's a great post ! It touches on many topics which resonate with my needs, and I really like the links to past discussions on some topics and the balanced blend of technical and social issues.

One thing which this post might be missing on the path to perfection is a little bit of prioritization. Overall, that's a somewhat long wishlist, maybe a bit much for a single year, so it would be nice if you could somehow point out what you feel is most important in it, even if it's just a rough categorization into large buckets (must/should/could style).

2 Likes
  • try to prevent team members from delaying RFCs by months or years with concerns or other things that never happen

What is this in reaction to? The RFC process is not a democracy and I for one think it's important to retain the ability to have blocking concerns, sometimes indefinitely.

2 Likes

so I often need to nuke its cache manually after upgrades

oh yes, this is true, the symptoms are pretty weird the first time you encounter them (re-compile of crates every time you build etc )

But in general this post feels like you were able to say what I feel like as a user. For example the "cargo folder" stuff and others feel to me like something that is just unreasonable. Yes there may be issues, yes there may be reasons for this to have taken time. But the end result (of doing nothing with the work provided) feel exactly like the post describes it. Thanks for that post!

Recently it feels like certain arguments are simply ignored or taken as "crying", so I'm starting to feel like saying nothing.

1 Like

[META]

Which is an unfortunate state of affairs. It's perfectly reasonable to desire something that others disagree with, eventually accepting that the desire will not be fulfilled (e.g., prefix await vs. postfix .await). That's adult behavior. Even if such situations occur repeatedly, the spirit of open-source contribution can remain, provided that the commentor does not become too dejected when the community decision-makers often disagree.

5 Likes

I don't have a fully formed wish list for Rust 2020, so I'm not going to blog about it.

But one thing that just occurred to me is that even with non-lexical lifetimes, Rust still doesn't allow mutably borrowing one part of self while immutably borrowing a disjoint part of self. It would be very nice to have this, as the status quo sometimes forces me to either refactor the code into unnatural shapes, or (the easier-but-technically-unsafe path), writing a macro to disable borrowck locally by casting to a (mutable) raw ptr and back to a (mutable) borrow i.e. unsafe { &my_obj as *const _ as &_ } and unsafe { &mut my_obj as *mut _ as &mut _ }. While the macro works and in this specific case there's not really a chance of illegal memory access (perhaps even in general, since the memory locations are disjoint?), it'd be very nice to get rid of it without deforming my code as that would obscure its intent.

Thoughts?

1 Like

I've never ran into a situation where I wasn't satisfied with

let Self { ref x, ref mut y } = *self;

and then having encapsulated operations on individual parts. The nice thing is this still holds even when Self is an enum, or the domain one is operating on goes much deeper than the data only held by Self directly. For more complicated things my associated functions are usually very simple and delegating to non-associated functions working on individual components of the Self. That also tends to leave the code in a reasonably self-documenting state.

I think there is not much movement in that space because there's a couple of solutions, and most of them have big impact on the language, and the problem space is small but diverse so a good direction is less apparent.

It could probably use some exploration via procedural macros to give people a better feel of the situation and what needs solving with what constraints.

5 Likes

There's a really good megathread on this that Niko started in 2018 when NLL was only almost production ready:

I've seen people occasionally raise this topic a few times since then, but only to repeat ideas already presented and explored much more thoroughly in that thread, giving me the impression this wasn't seen and read as widely as it should've been.

IMO @phaylon's post is basically correct about where that discussion ended up. However, I also believe that none of the suggested solutions was a net benefit over the status quo. Since you can't escape the need for the library author to explicitly opt-in to this disjointness guarantee for backwards compatibility, and it's always been possible to write a disjoint API by hand, the potential benefit of a language feature over a macro library ends up being very small.

1 Like

I'm not sure I want to assign priorities: they change during the year, unexpected things come up, contributors work on what they care most about. We've seen this happen with the past roadmaps. I'll take whatever of those is completed during the next year, and be happy about it.

You're right. I do have one specific case in mind that wasn't registered as a rfcbot concert and to be fair, it got resolved within months, not years. I don't want to name it because there's a large chance it will be interpreted as a personal attack, which is not my intention.

I replaced that part with a hopefully milder

There is an old idea of adding "borrow region" annotations (e.g. see this post) to allow finer-grained borrows without exposing private fields directly. There are some issue to resolve around syntax (can a single field be part of several regions? how regions should interact with traits? can we define regions for enums and tuples? etc.), but I think the core idea is a good one and worth pursuing.

Okay I think I explained myself poorly.

What I meant is, when using methods of some struct, some of which have &self and some of which have &mut self as a receiver (and respectively return & and &mut borrows), even with NLL I can't use them in any old random order in some fn/method using them. And that's even when the &self methods access completely different fields of Self than the &mut self methods do i.e. the set of fields accessed by the &self method is disjoint from the set of fields accessed by &mut self method.

This invites a question of course: why not split Self into multiple types? The answer is that conceptually that information belongs together and splitting up the types would make the code not more readable, but less. In fact it would be so much less readable that it makes a couple of unsafe usages look hackish-but-workable, rather than "In this code base? Never!".

This in turn leads me to shutting up borrowck a couple of times in the code by casting the (mutable) borrows to (mutable) raw ptrs and back again within an unsafe block. NLL has made a difference here, since I could remove a couple of instances of this unsafe code. But NLL didn't eliminate the need for it.

Have you read the linked message? Borrow regions aim to solve exactly this problem. In method signatures you will specify a finer grained borrow constraints, which will allow you to use non-conflicting methods without borrow checker yelling at you.

I did. I also saw that the initial post is from 2015, the last post is from roughly a year ago and nobody has said a word about it since, until your post. Until that changes I consider that idea pretty much dead.