Rust: Tracking issue for box_syntax

Created on 6 Apr 2018  路  12Comments  路  Source: rust-lang/rust

This is a tracking issue for the box_syntax feature, the special syntax for creating boxes, e.g. box 1usize (note: box patterns is separate and is tracked at at https://github.com/rust-lang/rust/issues/29641)

This was previously under the same tracking issues as placement (#22181/#27779) but I didn't want to remove it (yet) due to widespread usage in the compiler (Box::new is implemented in terms of it) and in the wider ecosystem (unlike <- etc which only had a handful of crates using it).

Things to decide:

  • how should box syntax be phased out?

    • how easy is it to remove box syntax as a language feature? Can we just describe it as "will never be stabilised in its current form as it's an internal implementation detail, may be stabilised under a new design of placement")?



      • if it were possible to remove it as a language feature, is it reasonable to do so without a replacement in the form of working placement?


      • if we want to keep box syntax internally, should we rename (but keep reserved) the keyword to something else to deliberately break users and indicate it shouldn't be used for placement?



    • is there any reason for users to use box syntax (apart from it looking nice) given Box::new is inline always, or does that not work?

  • if we decide to keep this, there are a number of unresolved questions in #22181 about the syntax behaviour

Note: when removing this, be careful not to remove the syntax entirely in order to not cause another case of https://github.com/rust-lang/rust/issues/50832

B-unstable C-tracking-issue T-lang

Most helpful comment

In most cases people just want to simplify the Box::news everywhere. I really want a shorter version and box syntax sounds like a great idea.
Is there a recent plan of stabilizing box syntax?

All 12 comments

Do I understand it correctly that the box syntax is dependent on placement-new (which has now been unapproved as an RFC)?

Personally I like the idea of having some syntactic sugar for creating something as common as a box (it does look nice). But obviously it would need to be built on something that works.

@spacekookie yes, the big deal for box syntax is placement new.

s there any reason for users to use box syntax (apart from it looking nice) given Box::new is inline always, or does that not work?

It doesn't optimize well, and even if it did, you would need some other way around it to avoid blowing up the stack in debug mode.
https://github.com/rust-lang/rust/issues/41160

is there any reason for users to use box syntax (apart from it looking nice) given Box::new is inline always, or does that not work?

So this is perhaps a bit of a weird usecase, but it is the only reason I have used box at all: I do a lot of no_std projects where the stack doesn't grow automatically. In these cases, using Box::new(MyLargeStruct) will overrun the limited amount of stack space by allocating MyLargeStruct on the stack and copying it to the allocated space. Allocating and initializing in place is critical.

The obvious alternative is to use the allocator directly and unsafely construct a Box from it, but that's annoying and ugly.

See example here: https://github.com/mark-i-m/os2/blob/2ab9d589a4463bd3133157b5c1a2f9f6735a3432/kernel/process/sched.rs#L76-L83

In most cases people just want to simplify the Box::news everywhere. I really want a shorter version and box syntax sounds like a great idea.
Is there a recent plan of stabilizing box syntax?

I think that there really isn't a convenient alternative for destructuring boxes without adding a lot of extra nesting. Personally, in very box-heavy code I would prefer that box destructuring be stabilized separately from box placement syntax. For instance, in this file I have 14 uses of the box destructuring syntax and only 1 of the box placement syntax. The code would become significantly less readable from the removal of box destructuring, whereas converting box <thing> with Box::new(thing) certainly doesn't bother me at all because the code is just as readable.

My thought then is that we should separate the tracking issue out for box destructuring so we can get that stabilized. The only reason we might not want to do this is if we want to create a general RFC for pattern matching items into Deref/DerefMut as described here. I don't intend to create said RFC at this time, but if someone else wants to do that then I think that is a viable alternative.

This could possible alleviate my usecase: https://crates.io/crates/copyless

@vadixidav box destructuring(/patterns) is already tracked at https://github.com/rust-lang/rust/issues/29641 (see mention of 'box patterns' in the issue description)

I was looking at Box::pin when I noticed, that box_syntax is using the prefix syntax. But for the very reason (box x).into() is ugly to type and chain, the await operator(?) is using postfix syntax, So, maybe, for the same reasons, box should use postfix syntax as well?

(box x).into()

vs

x.box.into()

At least, that is what came to my mind. Sorry if this is the wrong ticket or off topic, I just want to see rust getting continuously better and better :smiley:

x.box.into()

At least, that is what came to my mind. Sorry if this is the wrong ticket or off topic, I just want to see rust getting continuously better and better 馃槂

You could easily make a trait that adds a method and call it into_box or boxed:

x.boxed().into()

Implemented like:

trait Boxed {
    fn boxed(self) -> Box<Self>;
}

impl<T> Boxed for T {
    fn boxed(self) -> Box<Self> {
        Box::new(self)
    }
}

(adding type restrictions as needed)

For my use case, I'm less concerned with syntactic sugar (Box::new is fine) but with blowing up the stack (in both debug and release mode) as @oyvindln and @mark-i-m suggested.

If I have a struct like:

const SIZE: usize = 4096*4096;
#[derive(Copy, Clone)]
#[repr(C, align(4096))]
pub struct Pages([u8; SIZE]);

impl Default for Pages {
    fn default() -> Self {
        Pages([0u8; SIZE])
    }
}

Creating a Box<Pages> without overflowing the stack is quite hard. Consider the following example implementations:

pub fn with_new() -> Box<Pages> {
    Box::new(Pages([0u8; SIZE]))
}

pub fn with_box_syntax() -> Box<Pages> {
    box Pages([0u8; SIZE])
}

pub fn with_default() -> Box<Pages> {
    Default::default()
}

pub fn with_raw_alloc() -> Box<Pages> {
    use std::alloc::{alloc_zeroed, Layout, handle_alloc_error};
    let layout = Layout::new::<Pages>();
    let ptr = unsafe { alloc_zeroed(layout) };
    if ptr.is_null() {
        handle_alloc_error(layout);
    }
    unsafe { Box::from_raw(ptr as *mut Pages) }
}

with_new blows the stack in debug and release, while with_box_syntax and with_default blow the stack only in debug mode. Godbolt Link

So even something like @mark-i-m's example isn't guaranteed to work. Should the box syntax in with_box_syntax be guaranteed to not blow the stack (even in debug mode)?

Was this page helpful?
0 / 5 - 0 ratings