From 1716a835ddbf3381149c5976b7e72201fe48a40b Mon Sep 17 00:00:00 2001 From: blagovest Date: Tue, 30 May 2023 18:36:40 +0300 Subject: [PATCH 1/3] Edit template for RFC --- 0000-template.md | 196 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 144 insertions(+), 52 deletions(-) diff --git a/0000-template.md b/0000-template.md index a2ab4c4c8a6..24464a16172 100644 --- a/0000-template.md +++ b/0000-template.md @@ -1,97 +1,189 @@ -- Feature Name: (fill me in with a unique ident, `my_awesome_feature`) -- Start Date: (fill me in with today's date, YYYY-MM-DD) +- Feature Name: `virt_self` +- Start Date: `2023-05-30` - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary [summary]: #summary -One paragraph explanation of the feature. +Enable virtual dispatch of trait methods. # Motivation [motivation]: #motivation -Why are we doing this? What use cases does it support? What is the expected outcome? +Coming to Rust from an OOP language such as C++ one is told to favor composition over inheritance. In general, I think that's a great thing. However, lack of language features such as delegation and what this RFC proposes can make certain patterns more difficult to express than they should be. + +Consider the following situation. Say we have a trait `System` that models a given system. + +```rust +pub trait System { + fn op1(&self) -> SystemOp1; + fn op2(&self) -> SystemOp2; + // etc. +} +``` + +Assume that we now have a particular impl. `SystemA` which implements `op1` through a reference to `op2`. For instance, + +```rust +// asume the following +type SystemOp1 = i64; +type SystemOp2 = i64; + +pub struct SystemA { + +} + +impl System for SystemA { + fn op1(&self) -> SystemOp1 { + self.op2() * 5 + } + fn op2(&self) -> SystemOp2 { + 3 + } +} +``` + +Assume we now want to have a general purpose wrapper that allows us to somehow map the result of `op2`, say. For instance, + +```rust +pub struct DoubleOp2 { + sys: S, +} + +impl System for DoubleOp2 { + fn op1(&self) -> SystemOp1 { + self.sys.op1() + } + fn op2(&self) -> SystemOp2 { + self.sys.op2() * 2 + } +} +``` + +Clearly, this has the intended effect of changing `op2`. However, it also has the unintended effect of keeping `DoubleOp2::op1()` out of sync with `DoubleOp2::op2`. We got static dispatch when in this context virtual dispatch made more sense. + +Of course, in Rust, we usually associate dynamic dispatch with the `dyn` keyword. However, `dyn System` only gives a vtable for a particular impl without virtualizing any subsequent calls. In other words, calling `op1` through `DoubleOp2 as dyn System` will still call `SystemA::op2`. + +Of course, this behaviour may be what is desired. But sometimes, virtualizing at depth is more appropriate. Certainly when adopting OOP patterns. + +When I first stumbled upon this, I wondered if I could simply take `self` as `&dyn System` (or `Arc` or `Box` equivalent, etc.). Nope. + +The code I was working on required me to keep the trait `System` as one unit so I did not investigate possible ways to split it up. + +What I came up is passing a &dyn System virtualized self so now System looked like this + +```rust +pub trait System { + fn op1(&self, vself: &dyn System) -> SystemOp1; + fn op2(&self, vself: &dyn System) -> SystemOp2; +} +impl System for SystemA { + fn op1(&self, vself: &dyn System) -> SystemOp1 { + vself.op2() * 5 + } + fn op2(&self, vself: &dyn System) -> SystemOp2 { + 3 + } +} +``` + +And then calling `op2` with essentially another copy of `self`: +```rust +let system = DoubleOp2 {}; +system.op2(&system2); // works! +``` + +Of course this design is a bit clunky, but is very powerful. It allows complete control over what is virtualized and what isn't at any point in the call chain for every implementation. + +As I have been thinking about this more and more, I wondered what Rust with this in the language would look like. This RFC proposes a sample syntax (bikeshedding welcome, but please focus on the concepts). # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: +Essentially, we now allow `&virt self` as a shorthand for the above. + +```rust +pub trait System { + fn op1(&virt self) -> SystemOp1; + fn op2(&virt self) -> SystemOp2; +} +``` -- Introducing new named concepts. -- Explaining the feature largely in terms of examples. -- Explaining how Rust programmers should *think* about the feature, and how it should impact the way they use Rust. It should explain the impact as concretely as possible. -- If applicable, provide sample error messages, deprecation warnings, or migration guidance. -- If applicable, describe the differences between teaching this to existing Rust programmers and new Rust programmers. -- Discuss how this impacts the ability to read, understand, and maintain Rust code. Code is read and modified far more often than written; will the proposed feature make code easier to maintain? +The effect is that rust will manage two pointers - one concretely typed and one dynamic. The The concretely typed (i.e. `self`) follows the existing Rust rules. The dynamic one is either `self` as `dyn System` again or an existing dynamic `self` (this is like choosing `self` or `vself` in the previous section). -For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms. +Syntax could be e.g. +```rust +impl System for SystemA { + fn op1(&virt self) -> SystemOp1 { + // alternative 1 + virt(self).op2() * 5 + // alternative 2, I like this one most because it reminds me of C + self->op2() * 5 + // something else... + } + fn op2(&virt self) -> SystemOp2 { + 3 + } +} +``` + +Working with the second syntax, the difference between `self.op2()` and `self->op2()` would be static vs dynamic dispatch. In other words, it would allow us to call `DoubleOp2::op2()` from within `SystemA::op1()` when the call to it is made from `DoubleOp2::op1()`. + +If the called method is also declared virt, using `self->op2()` will retain the `vself` the same as originally passed to `op1`. Otherwise, it will replace it by `self as &dyn System`. + +Outside of traits, `a->b()` wouldn't compile. + +```[error-xxx] trait virtual methods can only be called virtually from within the trait``` + +Instead, only the traditional syntax of `a.b()` will be allowed and this would simply use a `vself` of `a as &dyn Trait`. + +I believe this feature will make Rust more user-friendly to people more inclined to think in OOP terms or who (like me) simply found themselves writing code in a domain that is very amenable to an OOP approach. + +The syntax changes are relatively minimal and there is no extra cost for code that does not use this feature. # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -This is the technical portion of the RFC. Explain the design in sufficient detail that: - -- Its interaction with other features is clear. -- It is reasonably clear how the feature would be implemented. -- Corner cases are dissected by example. +Implementing the above for immutable references is easy. However, mut references are inherently unsafe as we will be aliasing self initially. -The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work. +Solution is to either outright ban the above for `&mut self` or only allow it in unsafe contexts (e.g. treat it as `mut ptr`). # Drawbacks [drawbacks]: #drawbacks -Why should we *not* do this? +I fail to see any major drawbacks besides the override of `->`. # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives - Why is this design the best in the space of possible designs? + +It is intuitive and doesn't clutter the signatures unnecessarily. + - What other designs have been considered and what is the rationale for not choosing them? + +Explicit argument passing considered above. + - What is the impact of not doing this? -- If this is a language proposal, could this be done in a library or macro instead? Does the proposed change make Rust code easier or harder to read, understand, and maintain? -# Prior art -[prior-art]: #prior-art +The impact for experienced Rust users is probably low as they could figure their way to a solution. However, the impact for new Rust users coming from an OOP language may be great. -Discuss prior art, both the good and the bad, in relation to this proposal. -A few examples of what this can include are: +- If this is a language proposal, could this be done in a library or macro instead? Does the proposed change make Rust code easier or harder to read, understand, and maintain? -- For language, library, cargo, tools, and compiler proposals: Does this feature exist in other programming languages and what experience have their community had? -- For community proposals: Is this done by some other community and what were their experiences with it? -- For other teams: What lessons can we learn from what other communities have done here? -- Papers: Are there any published papers or great posts that discuss this? If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. +Admittedly, a lot of the above can be done with a macro but it would be awkward to use on the initial call site. Also, the generated code would necessarily have to expose the `vself` parameter and the IDE experience may not be that great. Also, a macro would find it hard to differentiate between mut and immutable references and will lead to subpar error messages. -This section is intended to encourage you as an author to think about the lessons from other languages, provide readers of your RFC with a fuller picture. -If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or if it is an adaptation from other languages. +# Prior art +[prior-art]: #prior-art -Note that while precedent set by other languages is some motivation, it does not on its own motivate an RFC. -Please also take into consideration that rust sometimes intentionally diverges from common language features. +OOP languages naturally support this via implicit or explicit virtual markers. # Unresolved questions [unresolved-questions]: #unresolved-questions -- What parts of the design do you expect to resolve through the RFC process before this gets merged? -- What parts of the design do you expect to resolve through the implementation of this feature before stabilization? -- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? +The case of `mut self`. # Future possibilities [future-possibilities]: #future-possibilities -Think about what the natural extension and evolution of your proposal would -be and how it would affect the language and project as a whole in a holistic -way. Try to use this section as a tool to more fully consider all possible -interactions with the project and language in your proposal. -Also consider how this all fits into the roadmap for the project -and of the relevant sub-team. - -This is also a good place to "dump ideas", if they are out of scope for the -RFC you are writing but otherwise related. - -If you have tried and cannot think of any future possibilities, -you may simply state that you cannot think of anything. - -Note that having something written down in the future-possibilities section -is not a reason to accept the current or a future RFC; such notes should be -in the section on motivation or rationale in this or subsequent RFCs. -The section merely provides additional information. +I have to think if the above interacts negatively with async but it doesn't seem to on a first pass. \ No newline at end of file From 3a8a4b747744160833625584f20007ca83fe7c28 Mon Sep 17 00:00:00 2001 From: blagovest Date: Tue, 30 May 2023 21:52:21 +0300 Subject: [PATCH 2/3] update with PR number --- text/3440-virt-self.md | 189 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 text/3440-virt-self.md diff --git a/text/3440-virt-self.md b/text/3440-virt-self.md new file mode 100644 index 00000000000..c7eeaae5c6e --- /dev/null +++ b/text/3440-virt-self.md @@ -0,0 +1,189 @@ +- Feature Name: `virt_self` +- Start Date: `2023-05-30` +- RFC PR: [rust-lang/rfcs#3440](https://github.com/rust-lang/rfcs/pull/3440) +- Rust Issue: [rust-lang/rust#3440](https://github.com/rust-lang/rust/issues/3440) + +# Summary +[summary]: #summary + +Enable virtual dispatch of trait methods. + +# Motivation +[motivation]: #motivation + +Coming to Rust from an OOP language such as C++ one is told to favor composition over inheritance. In general, I think that's a great thing. However, lack of language features such as delegation and what this RFC proposes can make certain patterns more difficult to express than they should be. + +Consider the following situation. Say we have a trait `System` that models a given system. + +```rust +pub trait System { + fn op1(&self) -> SystemOp1; + fn op2(&self) -> SystemOp2; + // etc. +} +``` + +Assume that we now have a particular impl. `SystemA` which implements `op1` through a reference to `op2`. For instance, + +```rust +// asume the following +type SystemOp1 = i64; +type SystemOp2 = i64; + +pub struct SystemA { + +} + +impl System for SystemA { + fn op1(&self) -> SystemOp1 { + self.op2() * 5 + } + fn op2(&self) -> SystemOp2 { + 3 + } +} +``` + +Assume we now want to have a general purpose wrapper that allows us to somehow map the result of `op2`, say. For instance, + +```rust +pub struct DoubleOp2 { + sys: S, +} + +impl System for DoubleOp2 { + fn op1(&self) -> SystemOp1 { + self.sys.op1() + } + fn op2(&self) -> SystemOp2 { + self.sys.op2() * 2 + } +} +``` + +Clearly, this has the intended effect of changing `op2`. However, it also has the unintended effect of keeping `DoubleOp2::op1()` out of sync with `DoubleOp2::op2`. We got static dispatch when in this context virtual dispatch made more sense. + +Of course, in Rust, we usually associate dynamic dispatch with the `dyn` keyword. However, `dyn System` only gives a vtable for a particular impl without virtualizing any subsequent calls. In other words, calling `op1` through `DoubleOp2 as dyn System` will still call `SystemA::op2`. + +Of course, this behaviour may be what is desired. But sometimes, virtualizing at depth is more appropriate. Certainly when adopting OOP patterns. + +When I first stumbled upon this, I wondered if I could simply take `self` as `&dyn System` (or `Arc` or `Box` equivalent, etc.). Nope. + +The code I was working on required me to keep the trait `System` as one unit so I did not investigate possible ways to split it up. + +What I came up is passing a &dyn System virtualized self so now System looked like this + +```rust +pub trait System { + fn op1(&self, vself: &dyn System) -> SystemOp1; + fn op2(&self, vself: &dyn System) -> SystemOp2; +} +impl System for SystemA { + fn op1(&self, vself: &dyn System) -> SystemOp1 { + vself.op2() * 5 + } + fn op2(&self, vself: &dyn System) -> SystemOp2 { + 3 + } +} +``` + +And then calling `op2` with essentially another copy of `self`: +```rust +let system = DoubleOp2 {}; +system.op2(&system2); // works! +``` + +Of course this design is a bit clunky, but is very powerful. It allows complete control over what is virtualized and what isn't at any point in the call chain for every implementation. + +As I have been thinking about this more and more, I wondered what Rust with this in the language would look like. This RFC proposes a sample syntax (bikeshedding welcome, but please focus on the concepts). + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Essentially, we now allow `&virt self` as a shorthand for the above. + +```rust +pub trait System { + fn op1(&virt self) -> SystemOp1; + fn op2(&virt self) -> SystemOp2; +} +``` + +The effect is that rust will manage two pointers - one concretely typed and one dynamic. The The concretely typed (i.e. `self`) follows the existing Rust rules. The dynamic one is either `self` as `dyn System` again or an existing dynamic `self` (this is like choosing `self` or `vself` in the previous section). + +Syntax could be e.g. +```rust +impl System for SystemA { + fn op1(&virt self) -> SystemOp1 { + // alternative 1 + virt(self).op2() * 5 + // alternative 2, I like this one most because it reminds me of C + self->op2() * 5 + // something else... + } + fn op2(&virt self) -> SystemOp2 { + 3 + } +} +``` + +Working with the second syntax, the difference between `self.op2()` and `self->op2()` would be static vs dynamic dispatch. In other words, it would allow us to call `DoubleOp2::op2()` from within `SystemA::op1()` when the call to it is made from `DoubleOp2::op1()`. + +If the called method is also declared virt, using `self->op2()` will retain the `vself` the same as originally passed to `op1`. Otherwise, it will replace it by `self as &dyn System`. + +Outside of traits, `a->b()` wouldn't compile. + +```[error-xxx] trait virtual methods can only be called virtually from within the trait``` + +Instead, only the traditional syntax of `a.b()` will be allowed and this would simply use a `vself` of `a as &dyn Trait`. + +I believe this feature will make Rust more user-friendly to people more inclined to think in OOP terms or who (like me) simply found themselves writing code in a domain that is very amenable to an OOP approach. + +The syntax changes are relatively minimal and there is no extra cost for code that does not use this feature. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +Implementing the above for immutable references is easy. However, mut references are inherently unsafe as we will be aliasing self initially. + +Solution is to either outright ban the above for `&mut self` or only allow it in unsafe contexts (e.g. treat it as `mut ptr`). + +# Drawbacks +[drawbacks]: #drawbacks + +I fail to see any major drawbacks besides the override of `->`. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +- Why is this design the best in the space of possible designs? + +It is intuitive and doesn't clutter the signatures unnecessarily. + +- What other designs have been considered and what is the rationale for not choosing them? + +Explicit argument passing considered above. + +- What is the impact of not doing this? + +The impact for experienced Rust users is probably low as they could figure their way to a solution. However, the impact for new Rust users coming from an OOP language may be great. + +- If this is a language proposal, could this be done in a library or macro instead? Does the proposed change make Rust code easier or harder to read, understand, and maintain? + +Admittedly, a lot of the above can be done with a macro but it would be awkward to use on the initial call site. Also, the generated code would necessarily have to expose the `vself` parameter and the IDE experience may not be that great. Also, a macro would find it hard to differentiate between mut and immutable references and will lead to subpar error messages. + +# Prior art +[prior-art]: #prior-art + +OOP languages naturally support this via implicit or explicit virtual markers. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +The case of `mut self`. + +# Future possibilities +[future-possibilities]: #future-possibilities + +I have to think if the above interacts negatively with async but it doesn't seem to on a first pass. \ No newline at end of file From 314d8878b502b74ab77a7dd0ff81a51c75b84fc9 Mon Sep 17 00:00:00 2001 From: blagovest Date: Tue, 30 May 2023 22:03:37 +0300 Subject: [PATCH 3/3] restore template --- 0000-template.md | 196 +++++++++++++---------------------------------- 1 file changed, 52 insertions(+), 144 deletions(-) diff --git a/0000-template.md b/0000-template.md index 24464a16172..a2ab4c4c8a6 100644 --- a/0000-template.md +++ b/0000-template.md @@ -1,189 +1,97 @@ -- Feature Name: `virt_self` -- Start Date: `2023-05-30` +- Feature Name: (fill me in with a unique ident, `my_awesome_feature`) +- Start Date: (fill me in with today's date, YYYY-MM-DD) - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary [summary]: #summary -Enable virtual dispatch of trait methods. +One paragraph explanation of the feature. # Motivation [motivation]: #motivation -Coming to Rust from an OOP language such as C++ one is told to favor composition over inheritance. In general, I think that's a great thing. However, lack of language features such as delegation and what this RFC proposes can make certain patterns more difficult to express than they should be. - -Consider the following situation. Say we have a trait `System` that models a given system. - -```rust -pub trait System { - fn op1(&self) -> SystemOp1; - fn op2(&self) -> SystemOp2; - // etc. -} -``` - -Assume that we now have a particular impl. `SystemA` which implements `op1` through a reference to `op2`. For instance, - -```rust -// asume the following -type SystemOp1 = i64; -type SystemOp2 = i64; - -pub struct SystemA { - -} - -impl System for SystemA { - fn op1(&self) -> SystemOp1 { - self.op2() * 5 - } - fn op2(&self) -> SystemOp2 { - 3 - } -} -``` - -Assume we now want to have a general purpose wrapper that allows us to somehow map the result of `op2`, say. For instance, - -```rust -pub struct DoubleOp2 { - sys: S, -} - -impl System for DoubleOp2 { - fn op1(&self) -> SystemOp1 { - self.sys.op1() - } - fn op2(&self) -> SystemOp2 { - self.sys.op2() * 2 - } -} -``` - -Clearly, this has the intended effect of changing `op2`. However, it also has the unintended effect of keeping `DoubleOp2::op1()` out of sync with `DoubleOp2::op2`. We got static dispatch when in this context virtual dispatch made more sense. - -Of course, in Rust, we usually associate dynamic dispatch with the `dyn` keyword. However, `dyn System` only gives a vtable for a particular impl without virtualizing any subsequent calls. In other words, calling `op1` through `DoubleOp2 as dyn System` will still call `SystemA::op2`. - -Of course, this behaviour may be what is desired. But sometimes, virtualizing at depth is more appropriate. Certainly when adopting OOP patterns. - -When I first stumbled upon this, I wondered if I could simply take `self` as `&dyn System` (or `Arc` or `Box` equivalent, etc.). Nope. - -The code I was working on required me to keep the trait `System` as one unit so I did not investigate possible ways to split it up. - -What I came up is passing a &dyn System virtualized self so now System looked like this - -```rust -pub trait System { - fn op1(&self, vself: &dyn System) -> SystemOp1; - fn op2(&self, vself: &dyn System) -> SystemOp2; -} -impl System for SystemA { - fn op1(&self, vself: &dyn System) -> SystemOp1 { - vself.op2() * 5 - } - fn op2(&self, vself: &dyn System) -> SystemOp2 { - 3 - } -} -``` - -And then calling `op2` with essentially another copy of `self`: -```rust -let system = DoubleOp2 {}; -system.op2(&system2); // works! -``` - -Of course this design is a bit clunky, but is very powerful. It allows complete control over what is virtualized and what isn't at any point in the call chain for every implementation. - -As I have been thinking about this more and more, I wondered what Rust with this in the language would look like. This RFC proposes a sample syntax (bikeshedding welcome, but please focus on the concepts). +Why are we doing this? What use cases does it support? What is the expected outcome? # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -Essentially, we now allow `&virt self` as a shorthand for the above. - -```rust -pub trait System { - fn op1(&virt self) -> SystemOp1; - fn op2(&virt self) -> SystemOp2; -} -``` +Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: -The effect is that rust will manage two pointers - one concretely typed and one dynamic. The The concretely typed (i.e. `self`) follows the existing Rust rules. The dynamic one is either `self` as `dyn System` again or an existing dynamic `self` (this is like choosing `self` or `vself` in the previous section). +- Introducing new named concepts. +- Explaining the feature largely in terms of examples. +- Explaining how Rust programmers should *think* about the feature, and how it should impact the way they use Rust. It should explain the impact as concretely as possible. +- If applicable, provide sample error messages, deprecation warnings, or migration guidance. +- If applicable, describe the differences between teaching this to existing Rust programmers and new Rust programmers. +- Discuss how this impacts the ability to read, understand, and maintain Rust code. Code is read and modified far more often than written; will the proposed feature make code easier to maintain? -Syntax could be e.g. -```rust -impl System for SystemA { - fn op1(&virt self) -> SystemOp1 { - // alternative 1 - virt(self).op2() * 5 - // alternative 2, I like this one most because it reminds me of C - self->op2() * 5 - // something else... - } - fn op2(&virt self) -> SystemOp2 { - 3 - } -} -``` - -Working with the second syntax, the difference between `self.op2()` and `self->op2()` would be static vs dynamic dispatch. In other words, it would allow us to call `DoubleOp2::op2()` from within `SystemA::op1()` when the call to it is made from `DoubleOp2::op1()`. - -If the called method is also declared virt, using `self->op2()` will retain the `vself` the same as originally passed to `op1`. Otherwise, it will replace it by `self as &dyn System`. - -Outside of traits, `a->b()` wouldn't compile. - -```[error-xxx] trait virtual methods can only be called virtually from within the trait``` - -Instead, only the traditional syntax of `a.b()` will be allowed and this would simply use a `vself` of `a as &dyn Trait`. - -I believe this feature will make Rust more user-friendly to people more inclined to think in OOP terms or who (like me) simply found themselves writing code in a domain that is very amenable to an OOP approach. - -The syntax changes are relatively minimal and there is no extra cost for code that does not use this feature. +For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms. # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -Implementing the above for immutable references is easy. However, mut references are inherently unsafe as we will be aliasing self initially. +This is the technical portion of the RFC. Explain the design in sufficient detail that: + +- Its interaction with other features is clear. +- It is reasonably clear how the feature would be implemented. +- Corner cases are dissected by example. -Solution is to either outright ban the above for `&mut self` or only allow it in unsafe contexts (e.g. treat it as `mut ptr`). +The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work. # Drawbacks [drawbacks]: #drawbacks -I fail to see any major drawbacks besides the override of `->`. +Why should we *not* do this? # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives - Why is this design the best in the space of possible designs? - -It is intuitive and doesn't clutter the signatures unnecessarily. - - What other designs have been considered and what is the rationale for not choosing them? - -Explicit argument passing considered above. - - What is the impact of not doing this? - -The impact for experienced Rust users is probably low as they could figure their way to a solution. However, the impact for new Rust users coming from an OOP language may be great. - - If this is a language proposal, could this be done in a library or macro instead? Does the proposed change make Rust code easier or harder to read, understand, and maintain? -Admittedly, a lot of the above can be done with a macro but it would be awkward to use on the initial call site. Also, the generated code would necessarily have to expose the `vself` parameter and the IDE experience may not be that great. Also, a macro would find it hard to differentiate between mut and immutable references and will lead to subpar error messages. - # Prior art [prior-art]: #prior-art -OOP languages naturally support this via implicit or explicit virtual markers. +Discuss prior art, both the good and the bad, in relation to this proposal. +A few examples of what this can include are: + +- For language, library, cargo, tools, and compiler proposals: Does this feature exist in other programming languages and what experience have their community had? +- For community proposals: Is this done by some other community and what were their experiences with it? +- For other teams: What lessons can we learn from what other communities have done here? +- Papers: Are there any published papers or great posts that discuss this? If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. + +This section is intended to encourage you as an author to think about the lessons from other languages, provide readers of your RFC with a fuller picture. +If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or if it is an adaptation from other languages. + +Note that while precedent set by other languages is some motivation, it does not on its own motivate an RFC. +Please also take into consideration that rust sometimes intentionally diverges from common language features. # Unresolved questions [unresolved-questions]: #unresolved-questions -The case of `mut self`. +- What parts of the design do you expect to resolve through the RFC process before this gets merged? +- What parts of the design do you expect to resolve through the implementation of this feature before stabilization? +- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? # Future possibilities [future-possibilities]: #future-possibilities -I have to think if the above interacts negatively with async but it doesn't seem to on a first pass. \ No newline at end of file +Think about what the natural extension and evolution of your proposal would +be and how it would affect the language and project as a whole in a holistic +way. Try to use this section as a tool to more fully consider all possible +interactions with the project and language in your proposal. +Also consider how this all fits into the roadmap for the project +and of the relevant sub-team. + +This is also a good place to "dump ideas", if they are out of scope for the +RFC you are writing but otherwise related. + +If you have tried and cannot think of any future possibilities, +you may simply state that you cannot think of anything. + +Note that having something written down in the future-possibilities section +is not a reason to accept the current or a future RFC; such notes should be +in the section on motivation or rationale in this or subsequent RFCs. +The section merely provides additional information.