Skip to content

Commit c6f3b0d

Browse files
committed
RFC: conventions for placement of unsafe APIs
1 parent e0acdf4 commit c6f3b0d

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

active/0000-unsafe-api-location.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
- Start Date: (fill me in with today's date, 2014-09-15)
2+
- RFC PR: (leave this empty)
3+
- Rust Issue: (leave this empty)
4+
5+
# Summary
6+
7+
This is a *conventions RFC* for settling the location of `unsafe` APIs relative
8+
to the types they work with, as well as the use of `raw` submodules.
9+
10+
The brief summary is:
11+
12+
* Unsafe APIs should be made into methods or static functions in the same cases
13+
that safe APIs would be.
14+
15+
* `raw` submodules should be used only to provide APIs directly on low-level
16+
representations.
17+
18+
# Motivation
19+
20+
Many data structures provide unsafe APIs either for avoiding checks or working
21+
directly with their (otherwise private) representation. For example, `string`
22+
provides:
23+
24+
* An `as_mut_vec` method on `String` that provides a `Vec<u8>` view of the
25+
string. This method makes it easy to work with the byte-based representation
26+
of the string, but thereby also allows violation of the utf8 guarantee.
27+
28+
* A `raw` submodule with a number of free functions, like `from_parts`, that
29+
construct `String` instances from various raw-pointer-based representations,
30+
as well as a `from_utf8` variant that does not actually check for utf8
31+
validity.
32+
33+
The problem is that currently, there is no consistent guideline about which of
34+
these APIs should live as methods/static functions associated with a type, and
35+
which should live in a `raw` submodule. Both forms appear throughout the
36+
standard library.
37+
38+
# Detailed design
39+
40+
The proposed convention is:
41+
42+
* When an unsafe function/method is clearly "about" a certain type (as a way of
43+
constructing, destructuring, or modifying values of that type), it should be a
44+
method or static function on that type. This is the same as the convention for
45+
placement of safe functions/methods.
46+
47+
* When an unsafe function/method is specifically for producing or consuming the
48+
underlying representation of a data structure (which is otherwise private),
49+
the API should use `raw` in its name. Specifically, `from_raw_parts` is the
50+
typical name used for constructing a value from e.g. a pointer-based
51+
representation.
52+
53+
* When an unsafe function/method is an unchecked variant of an otherwise safe
54+
API, it should be marked using an `_unchecked` suffix.
55+
56+
* `raw` submodules should only be used to provide APIs directly on low-level
57+
representations, separately from functions/methods for converting to/from such
58+
raw representations.
59+
60+
The benefit to moving unsafe APIs into methods (resp. static functions) is the
61+
usual one: you can gain easy access to these APIs merely by having a value of
62+
the type (resp. importing the type).
63+
64+
The perspective here is that marking APIs `unsafe` is enough to deter their use
65+
in ordinary situations; they don't need to be further distinguished by placement
66+
into a separate module.
67+
68+
# Drawbacks
69+
70+
One potential drawback of these conventions is that the documentation for a
71+
module will be cluttered with rarely-used `unsafe` APIs, whereas the `raw`
72+
submodule approach neatly groups these APIs. But rustdoc could easily be
73+
changed to either hide or separate out `unsafe` APIs by default.
74+
75+
More generally, these conventions give `unsafe` APIs more equal status with safe
76+
APIs. Whether this is a *drawback* depends on your philosophy about the status
77+
of unsafe programming. But on a technical level, the key point is that the APIs
78+
are marked `unsafe`, so users still have to opt-in to using them. *Ed note: from
79+
my perspective, low-level/unsafe programming is important to support, and there
80+
is no reason to penalize its ergonomics given that it's opt-in anyway.*
81+
82+
# Alternatives
83+
84+
There are two main alternatives:
85+
86+
* Rather than providing unsafe APIs directly as methods/static functions, they
87+
could be grouped into a single extension trait. For example, the `String` type
88+
could be accompanied by a `StringRaw` extension trait providing APIs for
89+
working with raw string representations. This would allow a clear grouping of
90+
unsafe APIs, while still providing them as methods/static functions and
91+
allowing them to easily be imported with e.g. `use std::string::StringRaw`.
92+
On the other hand, it still further penalizes the raw APIs (beyond marking
93+
them `unsafe`), and given that rustdoc could easily provide API grouping, it's
94+
unclear exactly what the benefit is.
95+
96+
* Use `raw` submodules to group together *all* manipulation of low-level
97+
representations. No module in `std` currently does this; existing modules
98+
provide some free functions in `raw`, and some unsafe methods, without a clear
99+
driving principle. The ergonomics of moving *everything* into free functions
100+
in a `raw` submodule are quite poor.
101+
102+
# Unresolved questions
103+
104+
The `core::raw` module provides structs with public representations equivalent
105+
to several built-in and library types (boxes, closures, slices, etc.). It's not
106+
clear whether the name of this module, or the location of its contents, should
107+
change as a result of this RFC. The module is a special case, because not all of
108+
the types it deals with even have corresponding modules/type declarations -- so
109+
it probably suffices to leave decisions about it to the API stabilization
110+
process.

0 commit comments

Comments
 (0)