Skip to content
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

doc: add a new language design faq #14370

Merged
merged 1 commit into from
May 25, 2014
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
4 changes: 2 additions & 2 deletions mk/docs.mk
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
DOCS := index intro tutorial guide-ffi guide-macros guide-lifetimes \
guide-tasks guide-container guide-pointers guide-testing \
guide-runtime complement-bugreport complement-cheatsheet \
complement-lang-faq complement-project-faq rust rustdoc \
guide-unsafe
complement-lang-faq complement-design-faq complement-project-faq rust \
rustdoc guide-unsafe

PDF_DOCS := tutorial rust

Expand Down
176 changes: 176 additions & 0 deletions src/doc/complement-design-faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
% Rust Design FAQ

This document describes decisions were arrived at after lengthy discussion and
experimenting with alternatives. Please do not propose reversing them unless
you have a new, extremely compelling argument. Note that this document
specifically talks about the *language* and not any library or implementation.

A few general guidelines define the philosophy:

- [Memory safety][mem] must never be compromised
- [Abstraction][abs] should be zero-cost, while still maintaining safety
- Practicality is key

[mem]: http://en.wikipedia.org/wiki/Memory_safety
[abs]: http://en.wikipedia.org/wiki/Abstraction_%28computer_science%29

# Semantics

## Data layout is unspecified

In the general case, `enum` and `struct` layout is undefined. This allows the
compiler to potentially do optimizations like re-using padding for the
discriminant, compacting variants of nested enums, reordering fields to remove
padding, etc. `enum`s which carry no data ("C-like") are eligible to have a
defined representation. Such `enum`s are easily distinguished in that they are
simply a list of names that carry no data:

```
enum CLike {
A,
B = 32,
C = 34,
D
}
```

The [repr attribute][repr] can be applied to such `enum`s to give them the same
representation as a primitive. This allows using Rust `enum`s in FFI where C
`enum`s are also used, for most use cases. The attribute can also be applied
to `struct`s to get the same layout as a C struct would.

[repr]: http://doc.rust-lang.org/rust.html#miscellaneous-attributes

## There is no GC

A language that requires a GC is a language that opts into a larger, more
complex runtime than Rust cares for. Rust is usable on bare metal with no
extra runtime. Additionally, garbage collection is frequently a source of
non-deterministic behavior. Rust provides the tools to make using a GC
possible and even pleasant, but it should not be a requirement for
implementing the language.

## Non-`Share` `static mut` is unsafe

Types which are [`Share`][share] are thread-safe when multiple shared
references to them are used concurrently. Types which are not `Share` are not
thread-safe, and thus when used in a global require unsafe code to use.

[share]: http://doc.rust-lang.org/core/kinds/trait.Share.html

### If mutable static items that implement `Share` are safe, why is taking &mut SHARABLE unsafe?

Having multiple aliasing `&mut T`s is never allowed. Due to the nature of
globals, the borrow checker cannot possibly ensure that a static obeys the
borrowing rules, so taking a mutable reference to a static is always unsafe.

## There is no life before or after main (no static ctors/dtors)

Globals can not have a non-constant-expression constructor and cannot have a
destructor at all. This is an opinion of the language. Static constructors are
undesirable because they can slow down program startup. Life before main is
often considered a misfeature, never to be used. Rust helps this along by just
not having the feature.

See [the C++ FQA][fqa] about the "static initialization order fiasco", and
[Eric Lippert's blog][elp] for the challenges in C#, which also has this
feature.

A nice replacement is the [lazy constructor macro][lcm] by [Marvin
Löbel][kim].

[fqa]: https://mail.mozilla.org/pipermail/rust-dev/2013-April/003815.html
[elp]: http://ericlippert.com/2013/02/06/static-constructors-part-one/
[lcm]: https://gist.github.com/Kimundi/8782487
[kim]: https://github.com/Kimundi

## The language does not require a runtime

See the above entry on GC. Requiring a runtime limits the utility of the
language, and makes it undeserving of the title "systems language". All Rust
code should need to run is a stack.

## `match` must be exhaustive

`match` being exhaustive has some useful properties. First, if every
possibility is covered by the `match`, adding further variants to the `enum`
in the future will prompt a compilation failure, rather than runtime failure.
Second, it makes cost explicit. In general, only safe way to have a
non-exhaustive match would be to fail the task if nothing is matched, though
it could fall through if the type of the `match` expression is `()`. This sort
of hidden cost and special casing is against the language's philosophy. It's
easy to ignore certain cases by using the `_` wildcard:

```rust,ignore
match val.do_something() {
Cat(a) => { /* ... */ }
_ => { /* ... */ }
}
```

[#3101][iss] is the issue that proposed making this the only behavior, with
rationale and discussion.

[iss]: https://github.com/mozilla/rust/issues/3101

## No guaranteed tail-call optimization

In general, tail-call optimization is not guaranteed: see for a detailed
explanation with references. There is a [proposed extension][tce] that would
allow tail-call elimination in certain contexts. The compiler is still free to
optimize tail-calls [when it pleases][sco], however.

[tml]: https://mail.mozilla.org/pipermail/rust-dev/2013-April/003557.html
[sco]: http://llvm.org/docs/CodeGenerator.html#sibling-call-optimization
[tce]: https://github.com/rust-lang/rfcs/pull/81

## No constructors

Functions can serve the same purpose as constructors without adding any
language complexity.

## No copy constructors

Types which implement [`Copy`][copy], will do a standard C-like "shallow copy"
with no extra work (similar to "plain old data" in C++). It is impossible to
implement `Copy` types that require custom copy behavior. Instead, in Rust
"copy constructors" are created by implementing the [`Clone`][clone] trait,
and explicitly calling the `clone` method. Making user-defined copy operators
explicit surfaces the underlying complexity, forcing the developer to opt-in
to potentially expensive operations.

[copy]: http://doc.rust-lang.org/core/kinds/trait.Copy.html
[clone]: http://doc.rust-lang.org/core/clone/trait.Clone.html

## No move constructors

Values of all types are moved via `memcpy`. This makes writing generic unsafe
code much simpler since assignment, passing and returning are known to never
have a side effect like unwinding.

# Syntax

## Macros require balanced delimiters

This is to make the language easier to parse for machines. Since the body of a
macro can contain arbitrary tokens, some restriction is needed to allow simple
non-macro-expanding lexers and parsers. This comes in the form of requiring
that all delimiters be balanced.

## `->` for function return type

This is to make the language easier to parse for humans, especially in the face
of higher-order functions. `fn foo<T>(f: fn(int): int, fn(T): U): U` is not
particularly easy to read.

## `let` is used to introduce variables

`let` not only defines variables, but can do pattern matching. One can also
redeclare immutable variables with `let`. This is useful to avoid unnecessary
Copy link
Contributor

Choose a reason for hiding this comment

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

Rust noob here. Not directly related to this guide, but I've been wondering about this and couldn't find any guidelines. It would be great if there was a small section in the tutorial with the pros and cons of these two approaches.

Copy link
Member

Choose a reason for hiding this comment

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

To be clear, @schmee , do you mean the shadowing behavior? What do you want guidance on?

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean, when is it possible to redeclare an immutable variable, and when should I in fact declare it mutable?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's always possible:

let a = 42;
println!("a = {}", a);
let a = 24;
println!("a = {}", a);

`mut` annotations. An interesting historical note is that Rust comes,
syntactically, most closely from ML, which also uses `let` to introduce
bindings.

See also [a long thread][alt] on renaming `let mut` to `var`.

[alt]: https://mail.mozilla.org/pipermail/rust-dev/2014-January/008319.html
15 changes: 8 additions & 7 deletions src/doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ li {list-style-type: none; }
* [Testing](guide-testing.html)
* [Rust's Runtime](guide-runtime.html)

# FAQs

* [Language Design FAQ](complement-design-faq.html)
* [Language FAQ](complement-lang-faq.html)
* [Project FAQ](complement-project-faq.html)
* [Code cheatsheet](complement-cheatsheet.html) - "How do I do X?"
* [How to submit a bug report](complement-bugreport.html)

Copy link
Contributor

Choose a reason for hiding this comment

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

Libraries are more important imo.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not about importance, it's about visibility. Really the only link to the libs you need is std, to get the search. But to find the faqs, you need to scroll past an endless list of crates.

Copy link
Member Author

Choose a reason for hiding this comment

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

(I'd be surprised if many even knew they existed)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea with cross crate searching it's not as relevant.

Copy link
Member

Choose a reason for hiding this comment

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

Yes please. This has been a pet peeve of mine for so long I'm surprised I never wrote a patch.

# Libraries

* [The standard library, `std`](std/index.html)
Expand Down Expand Up @@ -60,13 +68,6 @@ li {list-style-type: none; }

* [The `rustdoc` manual](rustdoc.html)

# FAQs

* [Language FAQ](complement-lang-faq.html)
* [Project FAQ](complement-project-faq.html)
* [Code cheatsheet](complement-cheatsheet.html) - "How do I do X?"
* [How to submit a bug report](complement-bugreport.html)

# External resources

* The Rust IRC channels on [irc.mozilla.org](http://irc.mozilla.org/)
Expand Down