TC0
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- title: "Edition policy for Rust scripting" author: TC start-date: 2026-02-20 date: 2026-04-05 url: https://hackmd.io/GqcIyY0aRTOThaumZ9YFuA --- # Edition policy for Rust scripting ## Preface There's an upcoming feature that will allow single-file Rust packages to be run with `cargo script.rs`. This document is about how and whether the edition of such files will be chosen when not explicitly specified and about the inside baseball of what processes need to be followed for selecting that behavior and changing it when new-edition toolchains are released. If you read nothing else, read the *[Proposed Next Steps][]*. ### Goal In this document, in the interest of addressing the many points that have been raised, I'll be discussing many process and jurisdictional matters. But my core goal is to convince the members of *all* teams, and particularly the members of the Cargo team, that the *[substantive concern][]* has merit — that we would all do better for the Project and for our users by not both 1) allowing the edition to not be specified and 2) committing ourselves to a policy of changing the default edition with each new-edition toolchain — at least, not yet. That is, I'd prefer for all of the process and jurisdictional matters to *not matter* because we all find a way to work together to find common ground and agreement about what's right for Rust. If you already know the background and want to skip to the substantive sections, first read *[Proposed Next Steps][]*, then *[Ergonomic Goals][]*, then the *[Substantive Concern][]*. Let me highlight as well the *[security consideration][]* that I raise, as that might affect the design space. ## Introduction Rust scripting, I predict, is going to be a big deal for Rust. I've been using it myself for real work; it's largely displaced my remaining use of Python. This is a credit to Ed Page, and I'm grateful to him for his work on this. My reservations about the edition policy are *because of* these high expectations. Scripting is going to be how many people encounter and use Rust. How cargo script handles editions affects the success and viability of editions, the lang team's ability to continue evolving the language, and our relationships with distributors. I'll advance three claims — that changing the default edition used to interpret a Rust file when a new-edition toolchain is released: 1. Is an edition item and any FCP setting policy for this must include the Edition team to be binding. 2. Is a language matter and any FCP setting policy for this must include the Language Design team to be binding. 3. Risks our ability to continue evolving the language with editions, the clarity of our messaging about what editions are, our reputation for stability, the success of editions, and our relationships with distributors. ## Upfront disclaimer: Not proposing to design **I don't propose to or care to design cargo script myself.** That's the job of the Cargo team; any feedback that I have about that (outside of this document) I submit only as a user. What I care about from the Edition and Lang side are the *invariants* that it upholds (or does not uphold) about the stability of how Rust files are interpreted over edition toolchain boundaries. ## Tour of the document After presenting the *[background][]*, I'll first cover the *[jurisdictional][]* question — why the Edition and Lang teams must be on an FCP that sets policy for changing the edition used to interpret Rust files. I'll then address the *[estoppel][]* arguments — why this concern isn't foreclosed by the RFC's prior acceptance by the Cargo team. I'll then turn to the *[ergonomic goals][]* that cargo script's design is pursuing — as mentioned, I don't want to design this feature, but it's important we understand the context of how it was designed and the tradeoffs that exist. I'll then present the *[substantive concern][]* — why the "editions are opt-in" invariant matters and what's at risk if we weaken it. This includes a discussion of *[alternatives][]* that would avoid this concern while keeping ergonomics in mind — these are discussed only because it's important to show that alternatives *exist*. There's a *[security consideration][]* hiding in there — be sure to see that. Finally, I'll cover in a *[Q&A][]* section various matters that didn't find a place elsewhere. Before that, though, since this is going to be a long walk, let's talk about possible next steps. <div id="next-steps"></div> ## Proposed next steps [proposed next steps]: #next-steps All of us, I think, want to ship cargo script. Is there a way we can do that ahead of settling the concerns I've raised and am detailing in this document? I think there is. Across the Project, when we want to stabilize something where a substantive concern has been raised, our favorite *trick* is to stabilize the subset that avoids the concern and leaves the doors open to all of the future directions we might want. In this case, that would mean, for now, requiring the edition to be specified in the frontmatter. I.e.: ```rust --- package.edition = "2024" --- fn main() {} ``` This would avoid all of the concerns this document discusses and leave all doors open. And it doesn't require stabilizing anything we otherwise wouldn't — all designs involve allowing the edition to be specified in the frontmatter in this way. We could later, backward compatibly, add ways to make this more ergonomic, such as creating these files and populating the edition with `cargo new` (as Eric Huss has suggested), allowing `cargo fix` to add the edition (already implemented), passing the edition on the command line or via a multi-call binary, finding a more compact line-oriented syntax for simple frontmatters and allowing `package` to be elided, etc. (See *[Alternatives][]*.) We could also, of course, later decide to allow the edition to be entirely omitted and default it to a fixed edition or to the then-current one. All doors would remain open. Aside from getting this stabilized, we'd derive another happy benefit: we'd get to see how people use stable Rust scripting. Putting this out there will help us learn things. Maybe I'm wrong, in this document, about how people will use it. Maybe the RFC is wrong about that. We'll know a lot more by putting this in the hands of stable Rust users. Then we'll be in a far better position to answer the hard questions and to start closing doors if needed. That said, this is just *one* path forward, proposed in the interest of offering a concrete plausible set of next steps. But I'm happy with *any* next steps that preserve the invariants about editions I discuss in this document. I trust that the Cargo team can find a solution that preserves acceptable ergonomics without risking the success and viability of editions. ### Would a partial stabilization require a new RFC? In discussion, in response to a [similar proposal][comment-similar-next-steps] for next steps by Niko, it was [suggested][comment-alternatives-need-rfc] that "any alternative will need to take this back to the RFC stage". For a partial stabilization that 1) doesn't involve stabilizing anything extra and 2) leaves fully open the door of stabilizing the rest of what was in the RFC, a demand that this return to the RFC stage would seem *unusual* in the context of Project norms. [comment-similar-next-steps]: https://github.com/rust-lang/rust/issues/152254#issuecomment-4046567652 [comment-alternatives-need-rfc]: https://github.com/rust-lang/rust/issues/152254#issuecomment-4047035184 ### Read next If you already know the background and want to skip the sections about jurisdiction and process, first read *[Proposed Next Steps][]*, then *[Ergonomic Goals][]*, then the *[Substantive Concern][]*. <div id="background"></div> ## Background [background]: #background [RFC 3502][] ("cargo-script"), building on [eRFC 3424][], introduced single-file Rust packages. The feature allows a Rust source file to be executed directly via `cargo script.rs` with an optional embedded manifest in the frontmatter ([RFC 3503][]) at the start of the file. Let's focus on the RFC's treatment of the default edition. As relevant here, it considered these options: - **"No default but error"**: Error when the edition is missing. This option was not selected "for now" but was explicitly kept as a future option. The RFC said: > Note: this is a reversible decision on an edition boundary. > > Disposition: Rejected *for now* due to the extra boilerplate for throwaway scripts and not following our pattern of how we are handling manifests differently than `Cargo.toml`. We might switch to this in the future if we find that the "latest as default" doesn't work as well as we expected. (Emphasis in original.) - **"Fixed default"**: Pin to a specific edition. The RFC said: > Note: this is a one-way door, we can't change the decision in the future based on new information. > > Disposition: Rejected because this effectively always requires the edition to be set. - **"Latest as default"**: Default to the current edition. This was selected. The RFC said: > Default to the `edition` for the current `cargo` version, assuming single-file packages will be transient in nature and users will want the current `edition`. However, we will produce a warning when no `edition` is specified, nudging people towards reproducible code. Ed Page proposed Cargo team FCP on 2024-04-23 and it completed FCP on 2024-05-07. The Lang team was not included and was not even CCed on the PR. The Edition team had not yet been chartered at that time (and the current members of the Edition team had full hands, as they had just at that time inherited an edition midway into the year). The [stabilization PR][], posted on 2026-01-30 and proposed for FCP that same day, similarly included neither team on the FCP. And neither Edition nor Lang was CCed. In one of its bullet points, the stabilization PR says: > * `package.edition` defaults to current edition, not 2015 edition, with a warning When I read this, I understood it to just mean that the edition would default to 2024, not 2015. But in discussion, I now understand the person making this proposal as wanting this stabilization to set as policy that the default edition will continue to be changed with each new-edition toolchain. I don't think the stabilization proposal, as written, was clear about this. Nonetheless, based on my earlier understandings about what might be desired, I timely raised my concern about the edition handling in [Rust issue #152254][] on 2026-02-06 before the stabilization entered FCP on 2026-02-10. <div id="jurisdiction"></div> ## Jurisdiction [jurisdiction]: #jurisdiction [jurisdictional]: #jurisdiction This section is about process and the responsibilities of teams. If this isn't your interest, skip to *[Ergonomic Goals][]*, then read the *[Substantive Concern][]*. ### The Edition team The Leadership Council chartered the Edition team in January 2025 ([`rust-lang/leadership-council#149`][edition-charter]), with the FCP completing unanimously on 2025-02-04. The council delegated "all details of edition handling" to the team. The charter explicitly includes that the Edition team is responsible for: > Setting and enforcing the minimum standards of quality, completeness, and timeliness for each edition item needed to make the edition a success overall. > > Accepting items into the edition, and removing items from the edition. > > Setting the name, timing of, and timeline for each edition in a way that maximizes the productive evolution of the language and the effectiveness of our processes while minimizing cost to our ecosystem. > > Communicating publicly about all aspects of the edition and its release. In recent discussion, some have characterized the role of the Edition team as being that of pure functionaries. As I understand, this was never true. It certainly wasn't true for the 2024 edition — we set binding policy and rejected edition items that teams had accepted. The chartering of the Edition team formalized this. Changing the default edition used to interpret a Rust file when a new-edition toolchain is released is an edition item. It can only occur at an edition boundary. It affects the nature and quality of the experience when adopting the new-edition toolchain. It should be documented in the Edition Guide. It affects the Edition team's ability to communicate what an edition is. It affects our ability to maximize the productive evolution of the language and our ability to minimize the cost to our ecosystem. It affects our relationships with distributors. It affects our ability to make the edition a success overall. (Each of these is discussed below in the *[substantive concern][]*.) It's within the Edition team's chartered scope. ### The Language Design team The Language Design team owns the form and interpretation of Rust programs. It owns — I claim — the language that people experience when they are "using Rust™". The scope of this ownership is driven by practical necessity. We're designers of an *embodied* language. We respond to reliance and actual breakage. If something is stabilized accidentally — even without our knowledge — and people rely on it, we have to navigate that. We therefore need influence over the levers that would overextend our perceived stability surface and thereby limit our ability to evolve the language. Consider: the `RUSTC_BOOTSTRAP` mechanism is a compiler feature. But I doubt we'd agree that the Compiler team could unilaterally decide to set `RUSTC_BOOTSTRAP=1` by default. I hope we wouldn't, anyway. That change would affect the *language*. No matter our protestations, it would make people using Rust™ believe and act as though the feature flags were stable and would prompt significant ecosystem reliance on them. We'd see the resulting real breakage when trying to make changes. That would affect our behavior and curtail our options. Or consider: it's within the power of any build tool to override the default lint levels. Would we agree that the Cargo team could unilaterally set all of our FCWs to `allow-by-default`? Or decide to curate themselves the things reported in deps? Again, I don't think so, and I hope we wouldn't. We carefully manage lint levels as a tool to evolve the language. It's *our* tool. While Cargo (or any build tool) *could* affect these things technically, in a Project context — where we come together to ship Rust™ — these decisions need the consent of the Lang team. (If, for technical reasons, the Cargo team wanted to remove the report-in-deps mechanism entirely, I could get behind that being their call. But as long as that mechanism exists, I don't think it's the Cargo team's call which of our language lints get reported in deps.) (Let me be clear, I'm not suggesting that the Compiler or Cargo teams *would* do any of these things. This is a jurisdictional analysis. The question is only whether it's within their unilateral discretion to do.) Let's turn to editions. Would we agree that the Cargo team, within its unilateral discretion, could change `cargo new` to stop populating the `edition` field and then change `cargo run/build/install` to use the current edition? That's pretty near what we're talking about here for cargo script. There really aren't *Rust source files* — there are only *Rust 2015 source files*, or *Rust 2024 source files*. Without knowing the edition, the language has not been fully specified. Again, we respond to reliance and actual breakage. If a lot of real code were out there that didn't specify the edition and was going to get the new one without opting-in when the edition shipped, then I think we'd hesitate a lot about making breaking changes in the edition. Once we do that, editions have lost their purpose and are no longer an effective tool for evolving the language. To preserve these tools and our ability to navigate the evolution of the language, we need one thing: to own the language people experience when using Rust™ — and I mean that TM literally. That trademark gives the Project exclusive control over that experience. It's natural that control is delegated to the Rust Language Design Team.[^reference-only-lang] [^reference-only-lang]: It's been proposed that perhaps the Lang team should only FCP changes to the Reference and that everything else would be in the jurisdiction of compiler or other teams. That'd be an interesting model. It would move Rust to a model closer to that of C or C++. The Lang team would throw the language "over the wall" every once in a while to rustc (or other compiler vendors) to do with what they please. Probably, in that model, I'd propose that we should move to *only* shipping new features in editions (as C and C++ effectively do). Regardless, that's not the model today. Today, the Lang team has a far wider mandate. <div id="estoppel"></div> ## The concern is not foreclosed [estoppel]: #estoppel This section is about process and when concerns can be raised. If this isn't your interest, skip to *[Ergonomic Goals][]*, then read the *[Substantive Concern][]*. ### The RFC itself invited reconsideration The RFC labeled the "latest as default" selection as a "reversible decision on an edition boundary." It contemplated switching to requiring an edition in the future: "If we learn this doesn't work as well as we want, this would allow us to switch to requiring the edition in the future." The summary section reiterates: "Based on feedback, we can switch to 'edition is required as of \<future\> edition'." Meanwhile, the RFC rejected the "fixed default" approach as a "one-way door, we can't change the decision in the future" — implying that the authors specifically designed their chosen approach to *not* be a one-way door. The RFC authors understood they were making a provisional choice. They designed the decision so it could be revisited. Treating it as irrevocable now contradicts the text of the RFC itself. Further, hedging in this way in an RFC removes the incentive to object strenuously at the RFC stage. Nobody wants to block progress and experimentation when the RFC is explicitly leaving the door open on a point. <div id="process-did-not-surface-concern-earlier"></div> ### The process didn't surface the concern earlier [the process didn't surface the concern earlier]: #process-did-not-surface-concern-earlier Neither the Edition team nor the Language Design team was on the FCP for RFC 3502 — the Edition team hadn't yet been chartered. The Lang team wasn't even CCed. The [stabilization PR][], posted on 2026-01-30 and proposed for FCP that same day, similarly included neither team on the FCP. And neither Edition nor Lang were CCed. In the stabilization, there's only one sentence in one bullet point about the edition behavior: > * `package.edition` defaults to current edition, not 2015 edition, with a warning The line is easy to miss — and in fact, I did entirely miss it even after I noticed the stabilization. Even once I saw it, I read it simply to mean that the edition would, for now, default to Rust 2024 (and not Rust 2015). Nonetheless, based on my earlier understandings of what might be desired, I timely raised my concern in [Rust issue #152254][] on 2026-02-06 before the stabilization entered FCP on 2026-02-10. Beyond its sparsity and ambiguity, there's no description in this bullet point of how any views shifted since the RFC — no discussion of taking a harder stance on this than the RFC did. It doesn't talk about anything learned since the RFC or about discussions with any other stakeholders such as the Lang and Edition teams or the effects this policy might have on them. It doesn't discuss how this policy isn't observable until the next edition. The mechanism for consulting a team is including that team on the FCP. Neither Lang nor Edition members have exhausted their rights to raise objections because neither team was consulted. <div id="being-consulted"></div> #### General awareness is different than being consulted [general awareness is different than being consulted]: #being-consulted Did people know, generally, that this was hanging out there? Yes. E.g., back on 2023-06-20, Josh [said][comment-josh-2023-concern]: > While reading the unstable documentation, I noticed that cargo script defaults to the current edition. > > I definitely appreciate the idea of not wanting to embed a manifest just to specify the edition. But I think that's going to make it harder to make breaking changes in editions, because everyone's scripts will break. > > Could we have a *shorter* way to specify edition, instead, such as `#!/usr/bin/cargo --edition 2024`? The [reply][comment-josh-2023-concern-reply], at the time, was that: > This is currently marked as an unresolved question within the tracking issue. If you want to see a lot of different approaches on this, you can check out the section on it in the [Pre-RFC](https://github.com/epage/cargo-script-mvs/blob/main/0000-cargo-script.md#edition) Later in the thread, on 2023-06-21, I [said][comment-tc-2023-concern]: > To echo what **Josh Triplett** said, it's really very important to not plan on `cargo-script` ever changing the default edition. Breaking things would be very off-brand for Rust, and it would put a future lang team in a terrible position. But much happened since 2023. On the Lang side, we added frontmatter (in [RFC 3503][]). Cargo script was put forward in an RFC that, as discussed in this document, left this door open in a way that discouraged raising a fuss about it at the RFC stage. And nightly implementation work proceeded quietly. Without being explicitly consulted, there's not an obvious *moment* where it's appropriate to raise this concern. There are many reasons not to do so unprompted. Not even being CCed, when it's easy to do so, causes one to suspect that one's input might not be *wanted* at that stage. And given how the RFC left the door open, it's always possible that things would change during the nightly implementation and experimentation work — maybe the item owner or the team would come around to this same point-of-view regardless. There's no point in arguing for something that still may be arrived at independently. The fact that this was known to be *out there* goes the other way too. The champion knew these concerns were out there. Since there was never any outreach to Lang or Edition on this — since there was no proactive attempt to check in on and address this known concern — it maybe shouldn't be *too* surprising that this was then raised at the time of stabilization. [comment-josh-2023-concern]: https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/cargo.20script.20and.20edition/near/368013463 [comment-josh-2023-concern-reply]: https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/cargo.20script.20and.20edition/near/368017509 [comment-tc-2023-concern]: https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/cargo.20script.20and.20edition/near/368122216 ### Process norms More broadly, feature RFCs have never been treated with finality in the Rust Project. We routinely revisit choices in these RFCs ahead of and during stabilization — often years later. With the benefit of new experience, new information, or hearing from new stakeholders, we reevaluate. There are drawbacks to that, and we might wish for things to work differently — for RFCs to be more binding, for concerns to be raised earlier, for stabilization to proceed without late-breaking questions. But those are separate policy discussions. For this, we should accept how the Project works, not how we might wish it worked. ### New experiences At the time the Cargo team accepted the cargo script RFC, I hadn't yet run an edition. The experience of running the 2024 edition is what has crystallized this concern for me. It's much more clear to me now than it was then how important the opt-in mechanism is for every aspect of making editions work. The RFC's own language anticipated that we might learn new things and revisit. We have, and we should. ### Championing Part of the champion's role is identifying stakeholders and proactively reaching out to address concerns early. That didn't happen with the Edition and Lang teams on this RFC. Championing is hard, and it's easy to miss stakeholders. I don't blame anyone for that, but I do think it's relevant in response to suggestions that the time to raise these concerns has passed. <div id="ergonomic-goals"></div> ## Understanding the ergonomic goals and tradeoffs [ergonomic goals]: #ergonomic-goals Cargo script aims to make Rust viable for lightweight scripting — the kind of tasks where people currently reach for Python. The design seeks to minimize boilerplate. The edition-float design seeks to serve this by allowing many scripts to work without any frontmatter without those scripts then being interpreted under the rules for an older edition. How this goal should be weighed against other goals will be relevant, so let's discuss some tradeoffs. ### Use case: Small tests and one-off programs People will use Rust scripting to write small tests and programs for one-off jobs. I've seen it argued that this is *the* key use case. Following from this, the argument goes that, for these "throwaway" scripts, it's not important to specify the edition. With this as the claimed key use case, then, it's argued that the ergonomic improvement from not having to specify the edition trumps the loss in stability and reproducibility and the other concerns. Clearly there is value in being able to be more concise. That makes sense to me. I know why that's appealing — every character between a novice and "hello world" matters. I hear that. I *agree* that three lines in every script is a real cost. But I disagree throwaway scripts will be the key use case — as I'm already finding in my own experience and as I'm hearing from others, I think this will be *one* use case of many (and that these other use cases will induce troublesome reliance on current-edition semantics). And even for small tests, demonstrations, and one-off programs, I don't think the picture is so simple or one-sided. Consider these scenarios: #### Scenario: Different hosts When I write one-off programs, I often end up running them on multiple machines. These machines often have different versions of Rust. I would never want to get arbitrary behavior due to this, so I'd always want the edition specified. #### Scenario: Confusing recipients In discussion, it was argued that one often wants to send a small program to a junior colleague to demonstrate some technique or behavior, and that it's important for that to be low overhead. While it should be low overhead, I'd never want to send a colleague, particularly a junior one, a Rust program without the edition specified. I wouldn't know the exact toolchain the person was using. If using a different one from mine, the behavior could be surprising and confusing — specifying the edition seems a small price to avoid that. <div id="online-resources"></div> #### Scenario: Sharing Rust files online and in documentation [online resources]: #online-resources One of the longstanding concerns about shipping editions more frequently has been about how a greater number of editions might affect people using online resources (such as StackOverflow) and outside (perhaps company-internal) documentation. To the degree that people post Rust code without specifying the edition, that presents a hazard for people learning or using Rust as they may come across such code and become confused when it doesn't work. To the degree that people write and post Rust scripts without specifying the edition (and where the edition is floating), that would increase this hazard. #### Scenario: Saving little tests Here's a personal experience. I keep a collection of little Rust tests and demonstrations going back over ten years. I keep these as simple `*.rs` files. To run them, I copy-and-paste them into a local playground environment. For years now, I've annotated each with a `compiletest`-style `//@ edition: <edition>` header. Even for little tests, the edition can matter, so I document it, and my tooling picks up on this to select the correct edition when creating `play.rust-lang.org` links. I'd suspect most who similarly save little tests and demonstrations would value reproducibility more than saving three lines. ### Use case: User and system utilities, cron jobs, systemd services, etc. Many people write and keep various little tools in `~/bin` or in `~/.local/bin`. System administrators and authors of container images often put such tools in `/usr/local/bin`. It can be convenient for these to exist in source form so they can be edited directly and shared across machines with different architectures. These tools are often run without a user present by cron jobs, systemd services, and so on. It'd be a real hazard for these to exist without the edition specified. ### Use case: One-off scripting by models Machine learning models are great at writing Rust to solve one-off problems — the strong type system helps them a lot. But writing out the files and directory structure for a crate is too much overhead (as it is for people), so they often reach for Python today. With Rust scripting, the models can reach for Rust. But models can get a bit confused about the edition. I'd always want the model to specify it so that it's checked and the model and the compiler are both clear on what edition is meant. Given recent trends, this and the next item seem likely to be growth areas for Rust. ### Use case: Scripting in skills for models When writing skills to improve the performance of a model, it's often helpful for those skills to include scripted tools. It's convenient for these to be single files — a perfect case for Rust scripting. Often these tools are written by the model itself and then only ever run by the model itself. The models almost always redirect stderr, e.g., to log it — the models prefer having things in files they can read back. But cargo script entirely suppresses the warning about the edition not being specified when stderr is redirected. ```sh cargo -Zscript src/main.rs 2>&1 | cat # No output. ``` This means that nobody may ever even see a warning about the edition not being specified. (Even if cargo didn't suppress the warning in this case, it still may never be seen. When a program returns successfully, the models often don't see a reason to check or print the build log — and they may choose to just suppress stderr entirely.) When building up and sharing a library of skills, I'd always want the edition specified, and I'd want tooling to enforce that it always is. ### Analysis: Conciseness is important, but so is stability We each are going to have our own use cases, of course. But given the ways I expect this will be used — many of which call for stability and reproducibility — it doesn't seem obvious to me that other important considerations (such as those we'll discuss below) must be set aside in service of being able to use the latest edition without any explicit edition indication. <div id="substantive-concern"></div> ## The concern: Editions must be opt-in [substantive concern]: #substantive-concern Editions let us evolve the language without breaking existing code. That's what we put on the banner. That's what we shout from the rooftops. That's what, as the Edition team, we remind the Foundation staff to say when we're releasing an edition (so that no reporter gets the idea that we're releasing Rust 2.0). If we break people's stuff when they upgrade to the new-edition toolchain, I just don't think we're upholding that. (And I don't think we get out of it by blaming the user.) That's an even bigger problem with cargo script than it would be with floating the edition for `cargo build` because, with scripts that may be backing systemd services or cron jobs, there may not even be a developer in the loop to see the breakage before it affects service. And we're going to be blind to this breakage before it happens because crater won't catch it for us. The Lang team responds to reliance and actual breakage. If putting breaking changes in an edition will break people's stuff, then we're going to hesitate to do it. That undermines the purpose of editions. ### Edition-relevant concerns: Editions as a product #### Edition invariants The original edition document, [RFC 2052][], committed that "editions do not split the ecosystem nor do they break existing code." In [RFC 3085][], Niko set out these edition invariants in priority-ordered form: 1. **"Editions enable 'stability without stagnation'"** — "Editions are opt-in, and so existing crates do not see these changes until they explicitly migrate over to the new edition." 2. **"Editions do not split the ecosystem"**. 3. **"Edition migration is easy and largely automated"**. 4. **"Users control when they adopt the new edition"** — "Part of making edition migration easy is ensuring that users can choose when they wish to upgrade. We recognize that many users, particularly production users, will need to schedule time to manage an Edition upgrade... We also want to enable upgrading to be done in a gradual fashion, meaning that it is possible to migrate a crate module-by-module in separate steps, with the final move to the new edition happening only when all modules are migrated." 5. **"Rust should feel like one language"**. 6. **"Uniform behavior across editions"**. 7. **"Editions are meant to be adopted"** — "we don't force the edition on our users, but we do feel free to encourage adoption of the edition through other means." If we float the edition somewhere that we're building or running code — e.g., in Rust scripts — then the editions aren't opt-in and users see the changes before "they explicitly migrate over to the new edition". If upgrading a toolchain version risks edition-scale breakage of all local Rust scripts without an edition set, that may cause users and will cause distributors to hesitate before adopting the new-edition toolchain. That will put more pressure on crates to maintain older MSRVs. Floating the edition does not let "users control when they adopt the new edition" in a meaningful sense. To be able to build crates that depend on the newer edition, the user will need to upgrade the toolchain. Without taking advanced nondefault steps to manage multiple parallel toolchains, the user will automatically be moved into the new edition for any scripts without explicit annotation. It seems clear that floating the edition is not aligned with these edition principles, so while I could go on, I won't belabor this point further. #### Our relationship with distributors From the edition side, what worries me the most about floating the edition is how it would affect our relationship with distributors and how it would influence the thinking of distributors when deciding whether to adopt our new-edition toolchains. Distributors have to think about how upgrading the toolchain affects every other package on the system and how it will affect users, system administrators, and container authors. Distributors need to avoid downstream breakage, but they can't know how each of these stakeholders is using a toolchain. The more risk there is of an upgrade breaking things, the less they're going to want to do it, and when they do it, the earlier they're going to want to do it in a release cycle. This mitigates their risk with more testing. The higher the risk, the less willing they'll be to merge an upgrade later. This was important in the release of Rust 2024. Our release date coincided closely with the freeze date for Debian Trixie. If they didn't include the Rust 2024 toolchain, then Rust for Linux would need to wait another 2-3 years before adopting the Rust 2024 edition. That would mean less testing for the new edition. It'd mean a major part of the ecosystem would be on Rust 2021 for a long time. It'd mean that Rust for Linux would be targeting their language feature requests to the old edition for years to come. It'd mean fewer crates would be willing to upgrade to Rust 2024. Since toolchains are the foundation for other packages, the Debian release managers prefer these to go in early. In making the case for why it'd be safe to bump the Rust version late in their window, we leaned heavily on Rust's unusually strong record of stability and on the fact that editions do not break existing code. In July 2024, I reached out on our behalf. I said: > New editions are opt-in, per crate. New Rust compilers continue to support old editions (forever) to avoid breaking any existing code. I offered "supporting documentation for a freeze exception, based on Rust's unusually strong history of stability guarantees."[^debian-evidence] The Debian Rust maintainer, Fabian Grünbichler, echoed these stability points when filing the freeze exception request ([Debian bug 1084048][debian-2]), citing Rust's track record — "the fallout is usually very small." Rust 1.85 was accepted into Trixie. [^debian-evidence]: The full message is available at the [Debian `pkg-rust-maintainers` archive][debian-1]. The release team discussion is in the [debian-release archive][debian-3]. If we start floating the edition, we can't make these representations. The distributors won't know how many systems, containers, users, or even other packages are out there with scripts that haven't specified the edition. They won't be persuaded that blaming the users who ignored a warning is good enough. They'll do the conservative thing and stay with an older toolchain. #### Edition testing We want users to have a good experience when adopting the new edition toolchain and when adopting the new edition. To ensure that good experience, we do significant testing of the new edition and of the edition migrations using crater. But Rust scripts are going to be *dark matter* in this universe. Neither the new edition nor the migrations are going to get tested by us. Users are going to be the first ones to see problems. The least we could do then, it would seem, would be to ensure that the user has opted-in to it. #### Online resources and outside documentation As mentioned [above][online resources], online and company-internal resources often share individual Rust files. To the degree that these don't specify the edition, that's a hazard for people learning or using Rust as they may become confused when these don't work. It's likely that Rust scripts, due to their self-contained convenience, will be widely posted. If, due to floating the edition, two people running the same script will get different behavior, that's a hazard, and that hazard makes it harder to justify releasing new editions. In a script, the edition isn't noise; it's signal. #### Making the edition a success The first and most important job of the Edition team is to "make the edition a success". That's what I repeated over and over again in working to ship Rust 2024. If we ship a new-edition toolchain that breaks people's stuff when they upgrade to it, I think people are going to complain — I think they might complain more loudly when we admit we knew that was possible, had no way to test for it, and did it anyway — I think they might suggest that was not a successful release of the edition, and I suspect I might agree with them. The edition is a *product*. This proposed policy to float the edition adds meaningful risk to the successful delivery of that product. It would worry me a lot to ship this edition item. ### Lang-relevant concerns: Evolving the language #### We respond to actual breakage As [RFC 3085][] said, "editions enable 'stability without stagnation'". Because they are opt-in, editions let us make otherwise-backward-incompatible changes to the language safely. A floating default edition erodes (or eliminates) that safety. On the Lang team, we respond to reliance and actual breakage. If people are relying on something, we go out of our way to not break it. We don't lean heavily on blaming the user. If the ecosystem fills up with Rust scripts that don't specify the edition, and if a new-edition toolchain is going to opt all of those scripts into that new edition, and if we can't even measure the degree of damage that will do because it won't show up on crater, it's hard for me to imagine that won't restrain us from making breaking changes across editions. If we did anyway, and then upon shipping a new edition, we started to receive feedback about everything we broke, it's even harder for me to imagine that we would *do it again*. Where would that leave us? At that point, either we would have to abandon the purpose of editions or Cargo would have to stop changing the default edition with future toolchains. That'd leave us with it having floated between some edition toolchains but being fixed to an older edition default for others. That'd be better than abandoning the purpose of editions, but doesn't seem great. I'd think it better if we could find a way to not end up in that position. #### System breakage with no developer in the loop Even aside from this edition policy question, Rust scripting worries me a bit in terms of Lang team process. Even within editions, we sometimes knowingly break things. We, of course, do this carefully and minimally. But when we do break something, we imagine, I think, that there's a developer in the loop. We imagine that someone comes into the office in the morning, runs `cargo build`, and sees, "oh, today's the day I need to address that thing they've been warning me about since last year". Or we imagine that a CI goes red. We imagine that we're breaking *builds*, not *systems*. With first-party support for Rust scripts, though, we're on the hook for breaking *systems*. Few test all the stuff on their systems when upgrading a toolchain. There are going to be scripts that have been quietly running in the background for years that, one poor day, are going to stop working because we broke something. Who knows what those scripts could be doing? It could be something important. In each edition, we bundle together a big set of breaking changes. And we don't use the kind of care that we use for within-edition breaking changes because, of course, we're expecting people to have to opt-in. Moving some script to a new edition drops all these breaking changes on it — all at once. That this breakage could affect *systems* with no developer in the loop makes it *more*, not less, important to me for Rust scripts to opt-in to editions and their associated breakage. #### The warning isn't and can't be sufficient Today, if you run a Rust script without an edition specified (and without redirecting stderr), you get this warning:[^earlier-warning] ``` $ cargo -Zscript src/main.rs warning: `package.edition` is unspecified, defaulting to the latest edition (currently `2024`) Compiling main v0.0.0 (/playground/src/main.rs) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s Running `/cache/cargo/x86_64-unknown-linux-gnu/debug/main` ``` The warning is one line. It's emitted with other routine build output (which can be substantial). It's easy to miss. And it doesn't actually warn people about the bad thing that's going to happen (their code is destined to break). Further, this warning is suppressed when stderr is redirected, e.g.: ```sh cargo -Zscript src/main.rs 2>&1 | cat # No output. ``` I don't think that any warning would be sufficient, due to the other points I'm raising, but to even begin to be plausible, I'd expect the warning to be big, loud, scary, and to take up a lot of lines — no less than what we do for an FCW. But I understand, I think, why it's instead implemented in this low-key way: because if it were as big, loud, and scary as it would need to be to have effect, then it would succeed in scaring people, and that would significantly lessen the reason to support not specifying the edition at all. If the warning is going to annoy and scare most people into writing the edition there, then why support not specifying it? Even this one-liner is attracting complaints (see [`rust-lang/cargo#16598`][cargo-16598]) — many seemed determined to find a way to suppress it. A bigger, louder warning would only attract more determination. [^earlier-warning]: At the time I raised this concern and started drafting this document, the warning instead said "warning: `package.edition` is unspecified, defaulting to `2024`". The recent change (see [`rust-lang/cargo#16676`][cargo-16676]), while an improvement, does not address or affect this concern. [cargo-16676]: https://github.com/rust-lang/cargo/pull/16676 <div id="alternatives"></div> ### Alternatives exist [alternatives]: #alternatives As mentioned, I don't propose to or care to design this feature myself. That's for the Cargo team to do. But presence or absence of plausible alternatives can be a good reason to do or not do something, so it's necessary to show that alternatives exist that would not risk the success or effectiveness of editions while still having acceptable ergonomics. Some of those options include:[^no-fixed-default] [^no-fixed-default]: From the list of alternatives, I'm eliding discussion of having a fixed default, such as 2015 or 2024. Nobody really likes this option because, in the fullness of time, this amounts to everyone needing to specify the edition anyway, so having a default at all only buys a few years of useful implicit behavior. But, to be clear, I have no *concerns* with a fixed default. This is the basis on which I'm happy for the stabilization as currently proposed (with a default of 2024) — minus any policy about changing that default later — to go forward. #### Error on missing edition Giving an error on a missing edition was "Alternative 1" in the RFC and it was kept as a future option that "we might switch to". The cost of this, today, is that the minimal script is then: ```rust --- package.edition = "2024" --- fn main() {} ``` What could we do to make that more ergonomic? Some options: #### Support `cargo fix` Being able to use `cargo fix` to automatically add the current edition would decrease the ergonomic cost of getting back an error. The error message could, of course, suggest running it and provide the exact invocation. Fortunately, `cargo fix` support for scripts has already been added (in [`rust-lang/cargo#16678`][cargo-16678]). [cargo-16678]: https://github.com/rust-lang/cargo/pull/16678 #### Allow bare `edition` Could cargo allow `package` to be elided? I.e.: ```rust --- edition = "2024" --- fn main() {} ``` That's a meaningful improvement. The RFC noted the same and mentioned this as a future possibility, saying: > We could allow `package` fields at the top level but: > > - It could make workspace root package detection messier. > - It limits us in our table / field selections. #### Later add line-oriented unfenced frontmatter We have both line comments and block comments, line doc comments and block doc comments. If we were to find that in a large number of cases the frontmatter was only needed for the edition and we wanted to shave lines, we could always later add a line-oriented version of frontmatter. Without meaning to bikeshed it, we could have something that rhymes with: ```rust #- edition = "2024" fn main() {} ``` That would be more minimal, and, on the Lang side, we could always add that later. #### Shebang proxies We could make `cargo` a multi-call binary and ship `cargo-<edition>` symlinks. The RFC notes that we'd risk accumulating many of these over many years and editions, but maybe new installations don't need to include the ones for all older editions. When run as `cargo script.rs` (i.e., not via the shebang), perhaps Cargo could parse the edition out of the shebang if it's there. This would get the minimal script down to: ```rust #!/bin/env cargo-2024 fn main() {} ``` #### Set busybox aside We could accept the edition as a command-line argument, e.g.: ```rust cargo --edition 2024 script.rs ``` The main trouble with that is busybox — it doesn't support `env -S` (allowing for arguments to a command in the shebang). Nearly all other systems that people actually use do. On those systems, the minimal script could be: ```rust #!/bin/env -S cargo --edition 2024 fn main() {} ``` (And as above, perhaps cargo could parse the edition out of the shebang if run as `cargo script.rs` — that would even work on busybox systems when the script is invoked that way.) Is it a deal breaker if people using busybox have to write the frontmatter version instead or have to invoke scripts with `cargo script.rs`? I don't know. That seems OK to me.[^shebang-overrated] [^shebang-overrated]: As an aside, and as Niko also [mentioned][comment-niko-shebang-overrated] in discussion, maybe we're focusing too much on use via shebangs. I've been using cargo script extensively, and I haven't yet once used it via shebang invocation. I always just run `cargo -Zscript script.rs`; Niko mentions this is how he uses it too. [comment-niko-shebang-overrated]: https://github.com/rust-lang/rust/issues/152254#issuecomment-4046567652 #### `cargo new script.rs` Eric Huss suggested that `cargo new` could create a file with the edition frontmatter already in place (this possibility is also mentioned in the RFC). It's OK, of course, for `cargo new` to default to the current edition, as it does today. This would make it easy for people to get going with a new script. That seems appealing. <div id="security-consideration"></div> #### Security aside: Cargo shouldn't be invoked by shebang anyway [security consideration]: #security-consideration Cargo script (especially in the way it's usually installed, via rustup) is not well-suited to shebang invocation anyway because it's a *leaky abstraction*, and this leak is security-relevant. ##### The `rust-toolchain.toml` attack Running a command implemented via a cargo shebang will read and respect `rust-toolchain` and `rust-toolchain.toml` files from the user's current directory *and any parent directory*. This can allow an attacker to trigger network requests, to perform a *downgrade attack* on the Rust toolchain, and to specify an arbitrary local path for the toolchain — resulting in *arbitrary code execution*. This attack works in the same way when running either `cargo script.rs` or `cargo run --manifest-path script.rs`. ##### The `.cargo/config.toml` attack Running `cargo script.rs` reads and respects a `.cargo/config.toml` file in the directory where the script is located or *in any parent directory of it*. An attacker with filesystem access to any of these directories also gets arbitrary code execution. If the user switches to the `--manifest-path` invocation, new attacks open. Consider: ```rust #!/bin/env -S cargo run --release --manifest-path --- package.edition = "2024" --- fn main() {} ``` The user might write this in order to set the `--release` profile. But this subtle change means that cargo now looks for `.cargo/config.toml` in the *user's* current directory or in any parent directory of it (as with the `rust-toolchain.toml` problem). In practice, that's the more serious risk (though each is concerning in its own way). ##### Security comparisons These represent a rather larger filesystem-based attack surface than is offered by Python or by Bash. Bash doesn't load any configuration from the current working directory, from the script's directory, or from any parent of either. It doesn't resolve commands from the script's directory. The attacker must control the environment, not just put files on the filesystem. Python has one filesystem-based attack vector: module shadowing from the script's directory. E.g., a `json.py` file placed next to a script that does `import json` will achieve code execution. But: - There is no parent directory traversal. - Only the script's directory can do this; not the current working directory. - Frozen core modules (e.g. `os`, `sys`, `io`) can't be shadowed. ##### Shebang invocation hides this risk Given these risks, one should always know explicitly that `cargo` is being invoked. Hiding this behind shebang invocation is not a good idea. (See also [RFC 3279][]; this is new surface area for that attack.) [RFC 3279]: https://github.com/rust-lang/rfcs/pull/3279 #### Summary of alternatives In this document, I'm not arguing for any of these as the final answer. I'm sure there are other good options. I trust that the Cargo team can find a solution that preserves acceptable ergonomics without risking the success and viability of editions. <div id="qa"></div> ## Q&A [q&a]: #qa ### Won't cargo script be too niche for this to matter? I expect that, with us shipping first-party support, Rust scripting will be widely adopted. The number of scripts affected by a floating edition will grow over time. Arguments that assume Rust scripting will remain niche enough for this not to matter are, in my view, underestimating the feature's appeal. ### Doesn't the Playground float the edition? Actually, not really. The Playground operates more in the manner of `cargo new` and `cargo fix`. Once you create a playground, it adds, e.g., `&edition=2024` to the URL. If you return later or share the link, you get the edition you had, not the latest edition. This is similar to what an alternative such as `cargo new script.rs` would do. It's interesting that even the designers of the Playground — which is obviously limited to little tests and demonstrations — recognized the need to pin the edition once the playground is created. ### Is there a difference between "the default floats" and "we change the default with each edition"? From a user perspective, a floating default and one that changes with each edition are indistinguishable. I'd suggest that, for the purposes of policy analysis, we therefore treat these equivalently as well. ### Is it contradictory to support the stabilization but oppose the edition policy? In raising [Rust issue #152254][], I said: > In some sense, the only fixed decisions at the time of stabilization are 1) that cargo script will work without an edition set and 2) that it will use Rust 2024 by default. We could always later decide to never change the default from Rust 2024. Due to that, if we're all happy with these two decisions (I am), I think it's OK for the stabilization to proceed. No need to block that. It's been argued that this position is contradictory — that I can't be OK with the stabilization but oppose the edition policy. I'm not sure that this is even an interesting argument — what would it change? But here goes: It wasn't clear to me when filing that issue that the [stabilization PR][] meant to include, as part of the scope of the FCP, a policy for changing the default edition used to interpret Rust files with the release of the new-edition toolchain. The PR description only says: > * `package.edition` defaults to current edition, not 2015 edition, with a warning When I saw it, I read it simply to mean that the edition would, for now, default to Rust 2024 (and not Rust 2015). I don't know what the members of the Cargo team had in mind when checking boxes, but I still don't believe that, as written, this text unambiguously goes beyond that. I had filed [Rust issue #152254][] not because I thought the stabilization was setting a policy — I didn't — but because I knew this matter was *out there* and the stabilization seemed a good time to bring it up. See *[The Process Didn't Surface the Concern Earlier][]* for more on this and *[General Awareness Is Different Than Being Consulted][]* for discussion on the challenges of finding the right *moment* to re-raise an outstanding concern. If we were to stabilize cargo script as otherwise currently proposed and then not change the default on the next edition, we'd be left with a permanent Rust 2024 default for scripts, which would be different than the permanent Rust 2015 default for `Cargo.toml` files. And, in the fullness of time, any fixed default amounts to everyone needing to specify the edition anyway, so it removes most of the value of having an implicit default. Do I think that's good? No. Do I understand why people wouldn't want to stabilize cargo script as-is if we're unlikely to change the default edition with the release of new-edition toolchains? Yes. This is why, in *[Proposed Next Steps][]*, I instead suggest a partial stabilization that requires the edition to be specified, leaving all doors open. But having a fixed default does not risk the success and viability of editions, so, with my Edition and Lang hats on, I would not raise any *concerns* about that outcome. ### Should we just "trust champions"? In discussion, Niko raised that while he would require the edition to be specified, that: > I also believe strongly that the Rust org needs to lean more into "champions" -- and in particular, giving champions latitude to drive fine-grained decisions. While champions are important, so are teams and team members. By reviewing every week a wide variety of issues, team members have a wider context. This wider context is important not just for high-level decisions but also for keeping low-level decisions consistent between different scopes of work. If teams were to fully exit the business of reviewing low-level decisions, we would end up with a very different — and less coherent — language and toolchain than what we have today. (And also, I do not agree that changing the default edition for Rust source files is a low-level or fine-grained decision — I think it's a rather high-level one with wide-ranging consequences.) Further, while putting these decisions in the hands of champions is an interesting future direction for the Project, it's not the process today. It'd be an error, I think, in the middle of trying to work through a specific concern, to abandon our current well-known and well-tested processes in favor of a new process that has not been tried or formally adopted. ## Conclusion I think Rust scripting is going to be big, that there are a lot of interesting use cases for it, and that it's how many people will use Rust. I'd like to see it ship. As discussed in *[Proposed Next Steps][]*, I think we can do that by using our favorite *trick* in the Project: stabilizing the subset that avoids the substantive concern and leaves all doors open. Let's require the edition to be specified in the frontmatter, for now. Then we'll get to see how people use stable Rust scripting. With that knowledge, we'll be in a far better position to answer the hard questions and to start closing doors if needed. Of course, that's just *one* possible path forward. I'm happy with *any* path forward that preserves the invariants about editions I discuss in this document. I trust that the Cargo team can find a solution that preserves acceptable ergonomics without risking the success and viability of editions. I appreciate Ed Page for his work on cargo script, and I appreciate his patience while I collected my thoughts in this document. [Rust issue #152254]: https://github.com/rust-lang/rust/issues/152254 [RFC 3502]: https://github.com/rust-lang/rfcs/pull/3502 [RFC 3503]: https://github.com/rust-lang/rfcs/pull/3503 [eRFC 3424]: https://github.com/rust-lang/rfcs/pull/3424 [stabilization PR]: https://github.com/rust-lang/cargo/pull/16569 [edition-charter]: https://github.com/rust-lang/leadership-council/issues/149 [RFC 3085]: https://rust-lang.github.io/rfcs/3085-edition-2021.html [RFC 2052]: https://rust-lang.github.io/rfcs/2052-epochs.html [cargo-16598]: https://github.com/rust-lang/cargo/issues/16598 [debian-1]: https://alioth-lists.debian.net/pipermail/pkg-rust-maintainers/2024-July/044870.html [debian-2]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1084048 [debian-3]: https://lists.debian.org/debian-release/2025/01/msg00735.html

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully