Skip to content

Commit

Permalink
Merge remote-tracking branch 'aturon/ownership-variants'
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcrichton committed Aug 28, 2014
2 parents 8194815 + 1851c2f commit c083dca
Showing 1 changed file with 156 additions and 0 deletions.
156 changes: 156 additions & 0 deletions active/0000-ownership-variants.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
- Start Date: (fill me in with today's date, 2014-08-13)
- RFC PR #: (leave this empty)
- Rust Issue #: (leave this empty)

# Summary

This is a *conventions RFC* for settling naming conventions when there
are by value, by reference, and by mutable reference variants of an
operation.

# Motivation

Currently the libraries are not terribly consistent about how to
signal mut variants of functions; sometimes it is by a `mut_` prefix,
sometimes a `_mut` suffix, and occasionally with `_mut_` appearing in
the middle. These inconsistencies make APIs difficult to remember.

While there are arguments in favor of each of the positions, we stand
to gain a lot by standardizing, and to some degree we just need to
make a choice.

# Detailed design

Functions often come in multiple variants: immutably borrowed, mutably
borrowed, and owned.

The canonical example is iterator methods:

- `iter` works with immutably borrowed data
- `mut_iter` works with mutably borrowed data
- `move_iter` works with owned data

For iterators, the "default" (unmarked) variant is immutably borrowed.
In other cases, the default is owned.

The proposed rules depend on which variant is the default, but use
*suffixes* to mark variants in all cases.

## The rules

### Immutably borrowed by default

If `foo` uses/produces an immutable borrow by default, use:

* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant.
* The `_move` suffix (e.g. `foo_move`) for the owned variant.

A consequence is that the iterator methods become: `iter`, `iter_mut`,
and `iter_move`.

**NOTE**: This convention covers only the *method* names for
iterators, not the names of the iterator types. That will be the
subject of a follow up RFC.

### Owned by default

If `foo` uses/produces owned data by default, use:

* The `_ref` suffix (e.g. `foo_ref`) for the immutably borrowed variant.
* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant.

### Exceptions

For mutably borrowed variants, if the `mut` qualifier is part of a
type name (e.g. `as_mut_slice`), it should appear as it would appear
in the type.

### References to type names

Some places in the current libraries, we say things like `as_ref` and
`as_mut`, and others we say `get_ref` and `get_mut_ref`.

Proposal: generally standardize on `mut` as a shortening of `mut_ref`.


## The rationale

### Why suffixes?

Using a suffix makes it easier to visually group variants together,
especially when sorted alphabetically. It puts the emphasis on the
functionality, rather than the qualifier.

### Why `move`?

Historically, Rust has used `move` as a way to signal ownership
transfer and to connect to C++ terminology. The main disadvantage is
that it does not emphasize ownership, which is our current narrative.
On the other hand, in Rust all data is owned, so using `_owned` as a
qualifier is a bit strange.

The `Copy` trait poses a problem for any terminology about ownership
transfer. The proposed mental model is that with `Copy` data you are
"moving a copy".

See Alternatives for more discussion.

### Why `mut` rather then `mut_ref`?

It's shorter, and pairs like `as_ref` and `as_mut` have a pleasant harmony
that doesn't place emphasis on one kind of reference over the other.

# Alternatives

## Prefix or mixed qualifiers

Using prefixes for variants is another possibility, but there seems to
be little upside.

It's possible to rationalize our current mix of prefixes and suffixes
via
[grammatical distinctions](https://github.com/rust-lang/rust/issues/13660#issuecomment-43576378),
but this seems overly subtle and complex, and requires a strong
command of English grammar to work well.

## No suffix exception

The rules here make an exception when `mut` is part of a type name, as
in `as_mut_slice`, but we could instead *always* place the qualifier
as a suffix: `as_slice_mut`. This would make APIs more consistent in
some ways, less in others: conversion functions would no longer
consistently use a transcription of their type name.

This is perhaps not so bad, though, because as it is we often
abbreviate type names. In any case, we need a convention (separate
RFC) for how to refer to type names in methods.

## `owned` instead of `move`

The overall narrative about Rust has been evolving to focus on
*ownership* as the essential concept, with borrowing giving various
lesser forms of ownership, so `_owned` would be a reasonable
alternative to `_move`.

On the other hand, the `ref` variants do not say "borrowed", so in
some sense this choice is inconsistent. In addition, the terminology
is less familiar to those coming from C++.

## `val` instead of `owned`

Another option would be `val` or `value` instead of `owned`. This
suggestion plays into the "by reference" and "by value" distinction,
and so is even more congruent with `ref` than `move` is. On the other
hand, it's less clear/evocative than either `move` or `owned`.

## `into_iter`

For the case of iteration, at least, it would make some sense to
signal ownership transfer by treating the owned version as a
conversion, `into_iter`. The main downside is that it would go against
the general convention for ownership variants (and cannot be used as
the general convention, because not all cases can be seen as
conversions).

Moreover, it's strange to see just the owning variant as a conversion
-- why not `as_iter`, `as_iter_mut`, and `into_iter`?

0 comments on commit c083dca

Please sign in to comment.