Skip to content

Commit

Permalink
Guide: unsafe
Browse files Browse the repository at this point in the history
  • Loading branch information
steveklabnik committed Aug 20, 2014
1 parent 1681f43 commit 1395166
Showing 1 changed file with 151 additions and 49 deletions.
200 changes: 151 additions & 49 deletions src/doc/guide.md
Expand Up @@ -535,7 +535,7 @@ arguments we pass to functions and macros, if you're passing more than one.
When you just use the curly braces, Rust will attempt to display the
value in a meaningful way by checking out its type. If you want to specify the
format in a more detailed manner, there are a [wide number of options
available](/std/fmt/index.html). For now, we'll just stick to the default:
available](std/fmt/index.html). For now, we'll just stick to the default:
integers aren't very complicated to print.

So, we've cleared up all of the confusion around bindings, with one exception:
Expand Down Expand Up @@ -3520,15 +3520,15 @@ out.
In systems programming, pointers are an incredibly important topic. Rust has a
very rich set of pointers, and they operate differently than in many other
languages. They are important enough that we have a specific [Pointer
Guide](/guide-pointers.html) that goes into pointers in much detail. In fact,
Guide](guide-pointers.html) that goes into pointers in much detail. In fact,
while you're currently reading this guide, which covers the language in broad
overview, there are a number of other guides that put a specific topic under a
microscope. You can find the list of guides on the [documentation index
page](/index.html#guides).
page](index.html#guides).

In this section, we'll assume that you're familiar with pointers as a general
concept. If you aren't, please read the [introduction to
pointers](/guide-pointers.html#an-introduction) section of the Pointer Guide,
pointers](guide-pointers.html#an-introduction) section of the Pointer Guide,
and then come back here. We'll wait.

Got the gist? Great. Let's talk about pointers in Rust.
Expand Down Expand Up @@ -4711,75 +4711,177 @@ fail.

# Macros

One of Rust's most advanced features is is system of **macro**s. While
One of Rust's most advanced features is its system of **macro**s. While
functions allow you to provide abstractions over values and operations, macros
allow you to provide abstractions over syntax. Do you wish Rust had the ability
to do something that it can't currently do? You may be able to write a macro
to extend Rust's capabilities.

You've already used one macro extensively: `println!`. When we invoke
You've already used one macro extensively: `println!`. When we invoke
a Rust macro, we need to use the exclamation mark (`!`). There's two reasons
that this is true: the first is that it makes it clear when you're using a
macro. The second is that macros allow for flexible syntax, and so Rust must
be able to tell where a macro starts and ends. The `!(...)` helps with this.

An example of even more advanced macro usage is in Rust's `regex` crate. This
implements **regular expressions* for Rust. Regular expressions provide a
powerful way to determine if a string matches a certain pattern, but they also
have their own syntax. Therefore, they're a perfect fit for Rust's macros.

Here's an example of using a regular expression in Rust:
Let's talk some more about `println!`. We could have implemented `println!` as
a function, but it would be worse. Why? Well, what macros allow you to do
is write code that generates more code. So when we call `println!` like this:

```{rust}
#![feature(phase)]
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;
let x = 5i;
println!("x is: {}", x);
```

The `println!` macro does a few things:

1. It parses the string to find any `{}`s
2. It checks that the number of `{}`s matches the number of other arguments.
3. It generates a bunch of Rust code, taking this in mind.

What this means is that you get type checking at compile time, because
Rust will generate code that takes all of the types into account. If
`println!` was a function, it could still do this type checking, but it
would happen at run time rather than compile time.

We can check this out using a special flag to `rustc`. This code, in a file
`print.rs`:

```{rust}
fn main() {
let re = regex!(r"^\d{4}-\d{2}-\d{2}$");
println!("Does our expression match? {}", re.is_match("2014-01-01"));
let x = "Hello";
println!("x is: {:s}", x);
}
```

This will print "Does our expression match? true". Now, we won't learn
everything there is to know about regular expressions in this tutorial. We can
consult [the regex crate's documentation](/regex/index.html) for more on that
later. For now, here's the important parts:
Can have its macros expanded like this: `rustc print.rs --pretty=expanded`, will
give us this huge result:

```{rust}
```{rust,ignore}
#![feature(phase)]
#[phase(plugin)]
extern crate regex_macros;
# fn main() {}
#![no_std]
#![feature(globs)]
#[phase(plugin, link)]
extern crate std = "std";
extern crate rt = "native";
use std::prelude::*;
fn main() {
let x = "Hello";
match (&x,) {
(__arg0,) => {
#[inline]
#[allow(dead_code)]
static __STATIC_FMTSTR: [::std::fmt::rt::Piece<'static>, ..2u] =
[::std::fmt::rt::String("x is: "),
::std::fmt::rt::Argument(::std::fmt::rt::Argument{position:
::std::fmt::rt::ArgumentNext,
format:
::std::fmt::rt::FormatSpec{fill:
' ',
align:
::std::fmt::rt::AlignUnknown,
flags:
0u,
precision:
::std::fmt::rt::CountImplied,
width:
::std::fmt::rt::CountImplied,},})];
let __args_vec =
&[::std::fmt::argument(::std::fmt::secret_string, __arg0)];
let __args =
unsafe {
::std::fmt::Arguments::new(__STATIC_FMTSTR, __args_vec)
};
::std::io::stdio::println_args(&__args)
}
};
}
```

These attributes allow the `regex_macros` crate to actually hook in to the
compiler itself and extend it with the regular expression syntax. Macros
are serious business!
Intense. Here's a trimmed down version that's a bit easier to read:

Next, let's look at the actual invocation:

```{rust}
# #![feature(phase)]
# #[phase(plugin)]
# extern crate regex_macros;
# extern crate regex;
# fn main() {
let re = regex!(r"^\d{4}-\d{2}-\d{2}$");
# }
```{rust,ignore}
fn main() {
let x = 5i;
match (&x,) {
(__arg0,) => {
static __STATIC_FMTSTR: =
[String("x is: "),
Argument(Argument {
position: ArgumentNext,
format: FormatSpec {
fill: ' ',
align: AlignUnknown,
flags: 0u,
precision: CountImplied,
width: CountImplied,
},
},
];
let __args_vec = &[argument(secret_string, __arg0)];
let __args = unsafe { Arguments::new(__STATIC_FMTSTR, __args_vec) };
println_args(&__args)
}
};
}
```

The `regex!` macro allows us to define a macro. inside of the `()`s, we have a
`r""` construct. This is a 'raw' string literal, that does no escaping of its
contents. This is a Rust feature, not a macros feature. Finally, the rest of
the insides, which is the regular expression itself. This regular expression
roughly translates to "four digits, followed by a hypen, followed by two
digits, followed by a hypen, followed by two digits."
Whew! This isn't too terrible. You can see that we still `let x = 5i`,
but then things get a little bit hairy. Three more bindings get set: a
static format string, an argument vector, and the aruments. We then
invoke the `println_args` function with the generated arguments.

This is the code (well, the full version) that Rust actually compiles. You can
see all of the extra information that's here. We get all of the type safety and
options that it provides, but at compile time, and without needing to type all
of this out. This is how macros are powerful. Without them, you would need to
type all of this by hand to get a type checked `println`.

For more on macros, please consult [the Macros Guide](/guide-macros.html).
Macros are a very advanced and still slightly experimental feature, and don't
require a deep understanding to use. The Guide can help you if you want to
write your own.
For more on macros, please consult [the Macros Guide](guide-macros.html).
Macros are a very advanced and still slightly experimental feature, but don't
require a deep understanding to call, since they look just like functions. The
Guide can help you if you want to write your own.

# Unsafe

Finally, there's one more concept that you should be aware in Rust: `unsafe`.
There are two circumstances where Rust's safety provisions don't work well.
The first is when interfacing with C code, and the second is when building
certain kinds of abstractions.

Rust has support for FFI, (which you can read about in the [FFI
Guide](guide-ffi.html)) but Rust can't guarantee that the C code will be safe,
like Rust's will. Therefore, Rust marks such functions with the `unsafe`
keyword, which indicates that the function may not behave properly.

Second, if you'd like to create some sort of shared-memory data structure, Rust
won't allow it, because memory must be owned by a single owner. However, if
you're planning on making access to that shared memory safe, such as with a
mutex, _you_ know that it's safe, but Rust can't know. Writing an `unsafe`
block allows you to ask the compiler to trust you. In this case, the _internal_
implementation of the mutex is considered unsafe, but the _external_ interface
we present is safe. This allows it to be effectively used in normal Rust, while
being able to implement functionality that the compiler can't double check for
us.

Doesn't an escape hatch undermine the safety of the entire system? Well, if
Rust code segfaults, it _must_ be because of unsafe code somewhere. By
annotating exactly where that is, you have a significantly smaller area to
search.

We haven't even talked about any examples here, and that's because I want to
emphasize that you should not be writing unsafe code unless you know exactly
what you're doing. The vast majority of Rust developers will only interact with
it when doing FFI, and advanced library authors may use it to build certain
kinds of abstraction.

# Conclusion

We covered a lot of ground here. When you've mastered everything in this Guide,
you will have a firm grasp of basic Rust development. There's a whole lot more
out there, we've just covered the surface. There's tons of topics that you can
dig deeper into, and we've built specialized guides for many of them. To learn
more, dig into the [full documentation
index](http://doc.rust-lang.org/index.html).

Happy hacking!

5 comments on commit 1395166

@bors
Copy link
Contributor

@bors bors commented on 1395166 Aug 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from brson
at steveklabnik@1395166

@bors
Copy link
Contributor

@bors bors commented on 1395166 Aug 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging steveklabnik/rust/guide_macros_and_unsafe = 1395166 into auto

@bors
Copy link
Contributor

@bors bors commented on 1395166 Aug 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

steveklabnik/rust/guide_macros_and_unsafe = 1395166 merged ok, testing candidate = 4dfdc69

@bors
Copy link
Contributor

@bors bors commented on 1395166 Aug 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 4dfdc69

Please sign in to comment.