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

RFC: conventions for ownership variants #199

Merged
merged 2 commits into from
Aug 28, 2014
Merged
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
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`.


Copy link
Member

Choose a reason for hiding this comment

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

✂️

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe ruining a joke, but I don't know what this means :)

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, there's an extra blank line here, so you should snip it 😄

## 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`?