-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add the boxed!() macro to "de-magic" box syntax #3057
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
- Feature Name: `boxed_macro` | ||
- Start Date: 2020-12-29 | ||
- RFC PR: [rust-lang/rfcs#3057](https://github.com/rust-lang/rfcs/pull/3057) | ||
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Introduces the `boxed` macro, which allows one to construct data directly on the heap. | ||
This provides an alternative method to box syntax that does not rely on magic syntax. In addition, | ||
if box syntax is significantly revised in the future, these changes could be applied to the `boxed` macro to | ||
prevent ecosystem breakage. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
At the moment, the only safe way of constructing data directly on the heap in Rust is via box syntax. | ||
The [`vec`](https://doc.rust-lang.org/src/alloc/macros.rs.html#37-47) macro is implemented in terms of it, | ||
and several other parts of the [standard library](https://doc.rust-lang.org/src/alloc/sync.rs.html#314-318) | ||
use it. | ||
[`Box::new`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.new) is the stable alternative to this; | ||
however, in certain cases, it may not inline properly, which can cause the value to be instantiated on the | ||
stack before being copied to the heap. This can blow up the stack. | ||
|
||
However, box syntax has attracted criticism in its use of magic syntax. It adds an unneeded level | ||
of complexity to the language for something as specific as instantiating a `Box`. The purpose of this macro is | ||
to "hide" this complexity from stable compiler users by integrating it into a macro, which is already a standard | ||
part of the Rust language. | ||
|
||
A benefit of this is that, if box syntax is significantly changed or even removed in the future, the `boxed` | ||
macro could be updated to reflect this change to prevent ecosystem breakage. For instance, if we decided to | ||
change box syntax to be similar to the `await` syntax (e.g. `x.box`), we could update the `boxed` macro to | ||
expand to `x.box` instead of `box x`. Then, ecosystem users of `boxed` would not be affected by this change | ||
at all. | ||
|
||
# Guide-level explanation | ||
[guide-level-explanation]: #guide-level-explanation | ||
|
||
The `boxed` macro would be used in almost exactly the same cases that box syntax would be used in. Consider | ||
the following case, where data must be directly allocated on the heap. | ||
|
||
```rust | ||
/// The Hectapus is like an octopus, but with 100 arms. | ||
#[derive(Debug)] | ||
struct Hectapus { | ||
arm_lengths: [u32; 100], | ||
} | ||
|
||
fn main() { | ||
// We can expect our hectapus tracking software to run on the embedded | ||
// computers hectapus scientists carry. Therefore, we need to initialize it | ||
// on the heap. | ||
let mut hectapus = box Hectapus { arm_lengths: [0; 100] }; | ||
|
||
for i in 0u32..100 { | ||
hectapus.arm_lengths[i as usize] = i * 2; | ||
} | ||
|
||
println!("{:?}", &hectapus); | ||
} | ||
``` | ||
|
||
The following regex can be applied to replace instance of box syntax with the `boxed` macro: | ||
|
||
``` | ||
s/box \(.*\)/boxed!(\1)/g | ||
``` | ||
|
||
# Reference-level explanation | ||
[reference-level-explanation]: #reference-level-explanation | ||
|
||
The `boxed` macro could be implemented in the standard library approximately as follows: | ||
|
||
```rust | ||
#[allow_internal_unstable(box_syntax)] | ||
macro_rules! boxed { | ||
($item: expr) => {{ | ||
box $item | ||
}} | ||
} | ||
``` | ||
|
||
Of course, if box syntax is ever updated, this macro should be as well. | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
Replacing instances of box syntax in the ecosystem with the `boxed` macro would likely be a source of | ||
annoyance. | ||
|
||
# Rationale and alternatives | ||
[rationale-and-alternatives]: #rationale-and-alternatives | ||
|
||
An alternative to this would be the simply stabilize box syntax, as this mostly serves as a way of | ||
"pseudo-stablizing" the syntax so its technical benefits can be used in the broader ecosystem. However, | ||
as this is likely years away, this macro serves as a way of bypassing box syntax. | ||
|
||
# Prior art | ||
[prior-art]: #prior-art | ||
|
||
Replacing special syntax with a more generalized one has already been done before with the `raw_ref_macros` | ||
feature in relation to `raw_ref_ops`. By replacing "magic" syntax with macro syntax, they were able to | ||
stabilize their feature much earlier. | ||
|
||
# Unresolved questions | ||
[unresolved-questions]: #unresolved-questions | ||
|
||
Should there be a lint to replace `box x` with `boxed!(x)`? | ||
|
||
# Future possibilities | ||
[future-possibilities]: #future-possibilities | ||
|
||
If a way to initialize memory on the stack without magic is introduced to the Rust language, `boxed` could be | ||
modified to support that. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we think of any real-world examples that aren't already served by the
vec!
macro that are likely to be big enough to overflow the stack?This function for example:
allocates a 10MiB array, and (currently) overflows in both debug and release mode.
The alternative with
box expr
(orboxed!
) would be:which doesn't overflow, but is equivalent to the already stable:
Playground link