--- title: "Lang design meeting 2024-12-18: Project goals review" tags: ["T-lang", "design-meeting", "minutes"] date: 2024-12-18 url: https://hackmd.io/yC5yKFpHQ2-FV-mfCnab8g --- # Project goals review 2024-12-18 ## Goals that have non-trivial asks and where I don't feel I know whether people want them ### Unsafe fields https://rust-lang.github.io/rust-project-goals/2025h1/unsafe-fields.html scottmcm: this is really making me hit the "what's the problem we're solving" wish again, both for the status quo and the shiny future. scottmcm: to use this as an example specifically, I think a great phrasing of the shiny future here could happen without saying any particular syntax, because the shiny future is "an unsafe fn without anything unsafe in the body is linted because it doesn't make sense". tmandry: I have a general feeling that this is a simplistic approach to the problem – and that the problem isn't as well defined as it could be, like Scott said. Josh: :+1: for including something in the shiny future about aspiring to have underlying unsafe actions for every unsafe block, such that an unsafe block without any underlying unsafe action is linted. However, I think this goal as specified is still a good one, an I think it's correctly specifying a problem statement and not just the solution. tmandry: I'm wondering how one should express things like "it's unsafe to write directly to this field but it has safe methods". Josh: For now, make a safe wrapper in the containing structure. Might be possible future work to provide a way to allow specific safe methods of the field's type to be directly used on the unsafe field without an unsafe block. NM: I think there's a real problem here and I feel like we've sat on it for an awful long time. Kind of perfect enemy of good vibes to me. scottmcm: I feel like this is an example where syntax gets my head caught in loops. I have wondered about unsafe types and other approaches. There was that arxiv paper that tried to find unnecessary uses of unsafe and scanned for things with unsafe fn but no unsafe in the body (and didn't realize that it was broken) was an example problem. TC: I'd probably push back a bit on the idea that an unsafe function must do unsafe things. That a function might be unsafe while not doing unsafe things seems a given due to our crate-level concept of unsafety. There's probably more we could do educationally here. TC: Separately, and more broadly, we've discussed various ideas about how to give crate authors more control over the user experience when using their crate -- e.g. perhaps letting them add their own lints, or their own extensions to r-a, or things like F# type providers -- and what's proposed here seems to fall along the lines. It's a way to communicate back to the rust compiler more about the crate's concept of unsafe so we can more precisely present that to the user. scottmcm: Strong disagree that it's education, because selfishly I like to think I know what I'm doing, but I wrote a use-after-free in core that wouldn't have happened if this feature (in some form) existed. TC: My pushback was on the idea that an unsafe fn should necessarily do unsafe things in its body, not against this feature necessarily. NM: meta note that we are short on time, but I disagree with most of what you all have said. =) JT: right now we have zero distinction between privacy and safety, we have no way to have "private for safety reasons" vs "private because unsafe to touch", makes it harder to write complex data structures. Whether it looks exactly like the proposed syntax is an interesting question. NM: I like that it had syntax because I think it is uncovering a real question -- how aligned *are* we on this? If not, I think it will get further in 6 months. Are we aligned on a design meeting as a reasonable outcome? TM: I'm struggling with how much it solves the problem, what other keywords we might want, whether it's as flexible as we would want, I might read an RFC and be convinced. Not ready to say we'll have it stable. scottmcm: Big fan of Josh's phrasing about separating visibility and safety. Conclusion: Go back to Jack-- * this is going to require lang-team involvement, lots of questions, temper expectations there * elaborate on the problem * 1 or 2 design meetings probably required to make sure we are well understanding Meta: update the template, shiny future is normative in the sense that if you dislike the *direction* of it, you shouldn't approve it, but the further it is in the future the more you should focus on the general shape. ### Field Projections https://rust-lang.github.io/rust-project-goals/2025h1/field-projections.html Josh: Huge :+1:. I think this solves *so many* problems we have, including many problems libs-api has. The design is going to need some iteration and discussion, but the design as proposed seems plausible and roughly the right shape. Observation: this has a notable syntax bikeshed (`->` vs `~` vs ...), we should distribute that bikeshed over the course of the goal rather than deferring it. But we should sill accept it. tmandry: I think we probably want this, but I think we will want something else for pin project specifically. scottmcm: unclear how to read the pin-specific parts of this in conjunction with people also (iirc) proposing `&pin` or similar. scottmcm: in favour in general, unclear how generally, and slightly scared of how it'll have to look. (scottmcm: with a time machine I'd be really tempted to make `.field` always project, rather than giving a place.) NM: agree with tmandry, I was wondering, should we "reference" this as part of the async goal? I think we want to invest work but I am worried that Benno will need an active partner, or that we as lang team need to devote regular time. tmandry: I'm also thinking about what the full picture looks like where we have a more ergonomic way of dereferencing a raw pointer and accessing a field through that. tmandry: Side note: I guess it could be `mystruct_ptr->myfield->otherfield.*`. NM: side note but I like thinking of `->` as a "map operator". I want to be able to do `vec.iter()->method().collect()`, but that is my weirdness. Josh: I think we *could* have a data structure that does that. I don't know if we want to do that for `Iterator` specifically, but we could. NM: my question is what support this needs to be successful. This strikes me as very ambitious. JT: doesn't seem that complicated to me relative to how much it brings, in terms of what it'll require from us. Usual asks like a design meeting, bit more bikeshedding for a brand new operator. The biggest ask is "is this the concept we're happy using for a whole class of problems, and tying other things into, and treating as an orthogonal language construct". SM: I can imagine tiers of support-- is this types team support for a new field pointer type? How big does this wants to go? NM: yeah the big challenge to me is like, "what should the trait look like, how will this work, etc" TM: well we haven't stabilized the try trait, we sometimes make things extensible without knowing how to do it. I'm still thikning about "how do we make this proposal a success". The things that I can see happening in 6 months -- I'd like to see an experimental impl, I think an RFC, but we're going to have to resolve the bikeshed, I don't feel confident saying we know the shape of traits we will want. Maybe we should say "we want to support the operation but are not going to stabilize." NM: That is not something I'd considered, but good point, we could just say "hey build something that works for the obvious examples and we'll argue about syntax and come back to the design of the trait later" Josh: :+1:, I would like things like `Field` to start out sealed to start with. SM: hmm, <https://rust-lang.github.io/rust-project-goals/2025h1/async.html?highlight=pin#the-next-6-months> is also talking about pin projection... TM: I feel like we are going to solve pin separately from this ultimately. I don't want to solve all these problems with this projection mechanism. JT: I'd love it if this can solve pin but I do expect the trait to start out sealed etc. The only thing we should plan on in 6 months is "does the syntax work for the handful of things in the stdlib to prove the point". We can generalize to third-party types later. TM: I'm somewhat skeptical of the syntax, it has a particular meaning in C/C++ that we are not going with. JT: That was the main rationale on the thread for proposing different syntax such as `~`. NM, sidenote: With the "customized self type" RFC, we kind of "quasi-committed" to the idea of `*mut` is *NOT* a smart pointer. I feel like the point of `->` is to really *be* map, in some sense, to extend field access (and so forth) to things that are NOT smart pointers. JT: Should we point the author to the discussion around `offset_of` and the syntax for accessing enum fields, and suggest that that should support whatever syntax we end up with? Consensus and overlap: * make clear that this is for experimentation, we don't expect to have perfect trait * elaborating the use cases -- is pin a major motivation? should Benno therefore try a different approach? * syntax won't necessarily be `->` * lang team sponsor for experiment-- Josh? ### Implement restrictions, prepare for stabilization https://rust-lang.github.io/rust-project-goals/2025h1/restrictions.html TC: Ship it. tmandry: This one makes sense to me since it's extending privacy with stuff you can already implement using privacy (but it's not always clear how). tmandry: I wanted to ask Niko what he thought about the `mut($vis)` on fields and how that might interact with his recent proposals for (im)mutable fields. NM: I'm ... mildly *something* about mut on fields. I don't know if I would be up to stabilize them without some more discussion. But some form of sealed trait I am very in favor of. Concern about mut fields would be something like this ```rust! pub struct Foo { bar: Bar } pub struct Bar { pub mut(crate) field: u8, private_field: u16, } impl Foo { fn bar(&mut self) -> &mut Bar { &mut self.bar } } ``` now this can be overwritten with a new bar, modifying `field`. I guess .. that's fine, in some sense, but with the `Overwrite` trait the hope was that we could actually do better here, so using `mut` seems to "intersect" (while not exactly *closing the door*). OTOH, it's been so annoying for so long that you can't do it... that I'm maybe willing to go for it and figure it out later. Side note that the syntax is hideous but I have no better suggestion. JT: Would this be the "exterior mutability" problem? :laughing: scottmcm: fan of finishing accepted stuff. JT: Ship it. I think settling the syntax is the primary question. We might also want to connect this with the unsafe fields proposal and ask about syntax consistency. NM: Thinking on it more I don't see any real problem with `mut(crate)` in terms of preventing us from having "truly immutable" fields in the future. TM: We may want to separate the stabilization of sealed traits and read-only fields. Good that the design considers both, but we may want to evaluate stabilization independently. NM bikesheds here: I keep thinking I want something like `#[impl(crate)]` ... SM: I am tempted to say we should just have `#[sealed]` on traits and call it a day. I could get convinced either way. Good question. Consensus: * Revise goal to be clear that motivation is sealed traits + read-only fields * Ask about whether author is ok to focus on sealed traits more than the latter, since I think there is more consensus on that tmandry observation: an ask for lang-team should be "bikeshed resolution" SM: does this interact with the types team? NM: only minimally SM: but lots of people want to scoped impls to do different impls from different crates NM: oh dear god yes that's a mess but not part of this particular goal SM: we want to be sure they are consistent ### Improve state machine codegen https://rust-lang.github.io/rust-project-goals/2025h1/improve-rustc-codegen.html TC: We should do something to this effect. We need to allocate time and commit to the bikeshed of course. TC: In general, I'd like for Rust to be a better compilation target -- I think we win things from that -- and this is part of that story. scottmcm: Big fan of doing something, somewhat opposed to lots of the approaches that have been brought up in the RFC. Happy to accept the goal under something that can thread that needle. tmandry: I agree we need a solution but the parameters of that solution feel very uncertain to me. The RFC is very focused around a particular solution and I don't feel convinced that it's the right one. I didn't find the couple of bullet points against tail calls in the RFC that compelling – more compelling might be to show samples of the same code expressed in different ways. JT: Very much appreciating that the proposed project goal here talks about the *underlying problem*, of making state machine codegen and other common patterns better. The goal allows for the possibility of improving optimization, recognizing patterns, adding syntax, or multiple of those. I would be concerned ifit prescribed One True Solution to this, but since it states the problem and intended exploration and *possible* paths, I would like to accept this. :+1: JT: Also just loving the idea of "C is not the limit of performance, we can do better". scottmcm: (replying to TC) Not a fan of thinking of rust as a compilation target, because forcing all our rules on the originating language really blocks lots of things that a language would want to do. TC: I'm not saying we should think of Rust as a compilation target; just that, incidentally, we should be a good one. NM: copying from the RFC to be sure everyone saw it =) ```rust fn loop_match() -> Option<u8> { loop match 1u8 { 1 => continue 2, 2 => continue 3, 3 => break Some(42), _ => None } } ``` scottmcm: And copying from <https://github.com/rust-lang/rfcs/pull/3720#issuecomment-2443280361> that I still think trying to smush int into match like this is bad, and think a better direction might be something more like ```rust finite_state_machine! { 'start: { continue 'two; } 'two: { continue 'three; } 'three: { break Some(42); } } ``` (as a builtin macro or keyword or something, not saying encoding it as a user-written `macro_rules` macro) Josh: @scottmcm: FWIW I don't think this RFC is specific to code translated from another language to Rust; it applies to writing high-performance code in general. scottmcm: @josh just replying to TC's comment. NM: This is proposing a lang-team experiment. Questions to ask are three: * Who would champion / serve as liaison? * TC: I would; it sounds like Josh would also. But the real challenge is addressing the concerns from those maybe less excited. * JT: I would. Also, averting a potential concern: I share the same concerns about not wanting to add language syntax unless we absolutely need it. I'll work with the author on that. I also think, separately, that we might want syntax for state machines, but we could experiment with that in crates and think about whether we want native syntax. * Folkert, in chat: as the RFC author, I'd also love to not introduce syntax; makes it a lot simpler. So if we can get to something that works well without it, great! (we care much more about the codegen output at the end than about the exact mechanism) * Who has grave concerns like "over my dead body" * Who has concerns they want to list and/or will it be disruptive? * scottmcm -- vocal that I have syntax concerns but in favor of the *general idea*, would be happy to find something, feels like a good thing for us to support as Rust * tmandry -- as an experiment, I think it's fine, I know that there was a lot of discussion I wasn't a part of, but I think it really needs good motivation for why we need *this* as the solution vs (say) tail calls or other approaches. Why is it structurally difficult to make this a reliable optimization that works in LLVM? The RFC I think covers some of that. The syntax isn't my favorite, I don't care *that* much, but I want to be sure that this is the best shape of the solution. * NM: in other words is having a dedicated syntax truly the right answer here? * TM: yes * NM -- roughly yes. I like the idea of being able to express finite state machines very directly and cleanly, reminds me of how we added `loop { }` instead of just writing `while true { }`. I don't really see us accepting the RFC (i.e., committing to syntax) in the next 6 months, I think it'll take more time to build consensus and/or be sure, but I'm very happy to see experimentation. I would be in favor of the syntax if it makes some key domain (especially one traditionally done in C) just read way *nicer*, even if it isn't strictly *needed*. * SM -- agree that I wouldn't want to see this in every Rust file I opened but if I saw it once in a while in places where it really fits, seems good Folkert de Vries (in chat): as the RFC author, I'd also love to not introduce syntax; makes it a lot simpler. So if we can get to something that works well without it, great! (we care much more about the codegen output at the end than about the exact mechanism) Consensus: Accept experiment; concerns about syntax but the author and liaison share those concerns. ### Null and enum-discriminant runtime checks in debug builds https://rust-lang.github.io/rust-project-goals/2025h1/null-enum-discriminant-debug-checks.html NM: I don't really know if this is lang, feels like a sanitizer thing, or it can start that way NM: next 6 months, add some flags, not really lang; alignment checks got - no design meeting is needed - or even a lang ### Declarative (`macro_rules!`) macro improvements https://rust-lang.github.io/rust-project-goals/2025h1/macro-improvements.html No objections/concerns, did not get time to read it today. ## Goals not really asking much of us ### Evaluate approaches for seamless interop between C++ and Rust ### Research: How to achieve safety when linking separately compiled code ### Rust Specification Testing ## Goals we've discussed in fair bits of detail and/or are old ### Bring the Async Rust experience closer to parity with sync Rust https://rust-lang.github.io/rust-project-goals/2025h1/async.html ### SVE and SME on AArch64 ### Expose experimental LLVM features for GPU offloading ### "Stabilizable" prototype for expanded const generics