Skip to content

Moved use of box_syntax in TRPL book. #23822

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

Merged
merged 1 commit into from
Apr 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/doc/trpl/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@
* [Lang items](lang-items.md)
* [Link args](link-args.md)
* [Benchmark Tests](benchmark-tests.md)
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
* [Conclusion](conclusion.md)
* [Glossary](glossary.md)
100 changes: 100 additions & 0 deletions src/doc/trpl/box-syntax-and-patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
% Box Syntax and Patterns

Currently the only stable way to create a `Box` is via the `Box::new` method.
Also it is not possible in stable Rust to destructure a `Box` in a match
pattern. The unstable `box` keyword can be used to both create and destructure
a `Box`. An example usage would be:

```
#![feature(box_syntax, box_patterns)]

fn main() {
let b = Some(box 5);
match b {
Some(box n) if n < 0 => {
println!("Box contains negative number {}", n);
},
Some(box n) if n >= 0 => {
println!("Box contains non-negative number {}", n);
},
None => {
println!("No box");
},
_ => unreachable!()
}
}
```

Note that these features are currently hidden behind the `box_syntax` (box
creation) and `box_patterns` (destructuring and pattern matching) gates
because the syntax may still change in the future.

# Returning Pointers

In many languages with pointers, you'd return a pointer from a function
so as to avoid copying a large data structure. For example:

```{rust}
struct BigStruct {
one: i32,
two: i32,
// etc
one_hundred: i32,
}

fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
Box::new(*x)
}

fn main() {
let x = Box::new(BigStruct {
one: 1,
two: 2,
one_hundred: 100,
});

let y = foo(x);
}
```

The idea is that by passing around a box, you're only copying a pointer, rather
than the hundred `int`s that make up the `BigStruct`.

This is an antipattern in Rust. Instead, write this:

```rust
#![feature(box_syntax)]

struct BigStruct {
one: i32,
two: i32,
// etc
one_hundred: i32,
}

fn foo(x: Box<BigStruct>) -> BigStruct {
*x
}

fn main() {
let x = Box::new(BigStruct {
one: 1,
two: 2,
one_hundred: 100,
});

let y: Box<BigStruct> = box foo(x);
}
```

This gives you flexibility without sacrificing performance.

You may think that this gives us terrible performance: return a value and then
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
smarter than that. There is no copy in this code. `main` allocates enough room
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
`foo` writes the value straight into the `Box<T>`.

This is important enough that it bears repeating: pointers are not for
optimizing returning values from your code. Allow the caller to choose how they
want to use your output.
86 changes: 2 additions & 84 deletions src/doc/trpl/pointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ fn main() {
```

We can mutably borrow `x` multiple times, but only if x itself is mutable, and
it may not be *simultaneously* borrowed:
it may not be *simultaneously* borrowed:

```{rust,ignore}
fn increment(x: &mut i32) {
Expand All @@ -595,8 +595,7 @@ Notice the signature of `increment()` requests a mutable reference.

## Best practices

Boxes are appropriate to use in two situations: Recursive data structures,
and occasionally, when returning data.
Boxes are most appropriate to use when defining recursive data structures.

### Recursive data structures

Expand Down Expand Up @@ -630,14 +629,6 @@ we don't know the size, and therefore, we need to heap allocate our list.
Working with recursive or other unknown-sized data structures is the primary
use-case for boxes.

### Returning data

This is important enough to have its own section entirely. The TL;DR is this:
you don't want to return pointers, even when you might in a language like C or
C++.

See [Returning Pointers](#returning-pointers) below for more.

# Rc and Arc

This part is coming soon.
Expand All @@ -654,79 +645,6 @@ This part is coming soon.

This part is coming soon.

# Returning Pointers

In many languages with pointers, you'd return a pointer from a function
so as to avoid copying a large data structure. For example:

```{rust}
struct BigStruct {
one: i32,
two: i32,
// etc
one_hundred: i32,
}

fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
Box::new(*x)
}

fn main() {
let x = Box::new(BigStruct {
one: 1,
two: 2,
one_hundred: 100,
});

let y = foo(x);
}
```

The idea is that by passing around a box, you're only copying a pointer, rather
than the hundred `int`s that make up the `BigStruct`.

This is an antipattern in Rust. Instead, write this:

```rust
#![feature(box_syntax)]

struct BigStruct {
one: i32,
two: i32,
// etc
one_hundred: i32,
}

fn foo(x: Box<BigStruct>) -> BigStruct {
*x
}

fn main() {
let x = Box::new(BigStruct {
one: 1,
two: 2,
one_hundred: 100,
});

let y: Box<BigStruct> = box foo(x);
}
```

Note that this uses the `box_syntax` feature gate, so this syntax may change in
the future.

This gives you flexibility without sacrificing performance.

You may think that this gives us terrible performance: return a value and then
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
smarter than that. There is no copy in this code. `main` allocates enough room
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
`foo` writes the value straight into the `Box<T>`.

This is important enough that it bears repeating: pointers are not for
optimizing returning values from your code. Allow the caller to choose how they
want to use your output.

# Creating your own Pointers

This part is coming soon.
Expand Down