Skip to content

Commit d963465

Browse files
Add RFC for return type attributes
1 parent cfa5d53 commit d963465

File tree

1 file changed

+249
-0
lines changed

1 file changed

+249
-0
lines changed

text/0000-return-type-attrs.md

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
- Feature Name: `return_type_attrs`
2+
- Start Date: 2021-11-25
3+
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
4+
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Allow attributes in function return type position. For example:
10+
11+
```rust
12+
fn sum(x: u8, y: u8) -> #[some_attr] u8 {
13+
x + y
14+
}
15+
```
16+
17+
# Motivation
18+
[motivation]: #motivation
19+
20+
Currently the whole function can be annotated with a macro attribute:
21+
22+
```rust
23+
#[some_attr]
24+
fn example() { .. }
25+
```
26+
27+
As well as individual function parameters (introduced in [RFC2565]):
28+
29+
[RFC2565]: 2565-formal-function-parameter-attributes.md
30+
31+
```rust
32+
fn example(#[attr] input: String, #[attr] x: u8) { .. }
33+
```
34+
35+
However function return types currently cannot be annotated, which forces DSLs
36+
to resort to function attributes, for example:
37+
38+
```rust
39+
#[return_format = "json"]
40+
fn example(#[param = "q"] query: String, #[page = "p"] page: u64) -> Vec<Page> {
41+
..
42+
}
43+
```
44+
45+
Especially for functions with many parameters this can result in the annotation
46+
that is meant for the return type to be several lines apart from the return
47+
type that it actually describes:
48+
49+
```rs
50+
#[return_format = "json"]
51+
fn example(
52+
#[param = "q"] query: String,
53+
#[param = "p"] page: u64,
54+
#[param = "c"] count: u64,
55+
#[param = "o"] order_by: Column,
56+
) -> Vec<Page> {
57+
..
58+
}
59+
```
60+
61+
For such cases return type attributes could provide more clarity:
62+
63+
```rs
64+
fn example(
65+
#[param = "q"] query: String,
66+
#[param = "p"] page: u64,
67+
#[param = "c"] count: u64,
68+
#[param = "o"] order_by: Column,
69+
) -> #[json] Vec<Page> {
70+
..
71+
}
72+
```
73+
74+
Since function parameters already can be annotated this can be regarded as the
75+
next logical step towards more expressive and intuitive DSLs. The motivation
76+
for the introduction of parameter attributes outlined in [RFC2565] largely
77+
applies to return type attributes as well, since they would also be useful for
78+
property based testing, interoperability with other languages and optimization
79+
annotations.
80+
81+
# Guide-level explanation
82+
[guide-level-explanation]: #guide-level-explanation
83+
84+
Return types of `fn` definitions may have attributes attached to them. Thereby,
85+
additional information may be provided.
86+
87+
For the purposes of illustration, let's assume we have the attribute
88+
`#[apple]` available to us.
89+
90+
## Basic examples
91+
92+
The syntax for attaching attributes to return types is shown in the snippet below:
93+
94+
```rust
95+
// Free functions:
96+
fn foo() -> #[apple] u32 { .. }
97+
98+
impl Alpha { // In inherent implementations.
99+
fn bar() -> #[apple] u8 { .. }
100+
101+
..
102+
}
103+
104+
impl Beta for Alpha { // Also works in trait implementations.
105+
fn bar() -> #[apple] u8 { .. }
106+
107+
..
108+
}
109+
```
110+
111+
## Trait definitions
112+
113+
An `fn` definition doesn't need to have a body to permit return type attributes.
114+
Thus, in `trait` definitions, we may write:
115+
116+
```rust
117+
trait Beta {
118+
fn bar(&self) -> #[apple] u8;
119+
}
120+
```
121+
122+
## `fn` types
123+
124+
You can also use attributes in function pointer types.
125+
For example, you may write:
126+
127+
```rust
128+
type Foo = fn() -> #[apple] u8;
129+
```
130+
131+
## Unit return type
132+
133+
When annotating the unit return type `()` must be specified explicitly. For
134+
example:
135+
136+
```rust
137+
fn foo() -> #[apple] () {
138+
..
139+
}
140+
```
141+
142+
Attempting the following:
143+
144+
```rust
145+
fn foo() -> #[apple] {
146+
..
147+
}
148+
```
149+
150+
will result in a compile error:
151+
152+
```
153+
error: return type attributes require an explicit return type
154+
fn foo() -> #[apple] {
155+
^ expected ()
156+
```
157+
158+
## Built-in attributes
159+
160+
Attributes attached to return types do not have an inherent meaning in
161+
the type system or in the language. Instead, the meaning is what your
162+
procedural macros, the tools you use, or what the compiler interprets certain
163+
specific attributes as.
164+
165+
As for the built-in attributes and their semantics, we will, for the time being,
166+
only permit the following attributes on return types:
167+
168+
- Lint check attributes, that is:
169+
`#[allow(C)]`, `#[warn(C)]`, `#[deny(C)]`, `#[forbid(C)]`,
170+
and tool lint attributes such as `#[allow(clippy::foobar)]`.
171+
172+
All other built-in attributes will be rejected with a semantic check.
173+
For example, you may not write:
174+
175+
```rust
176+
fn foo() -> #[inline] u32 { .. }
177+
```
178+
179+
180+
# Reference-level explanation
181+
[reference-level-explanation]: #reference-level-explanation
182+
183+
TODO
184+
185+
<!--
186+
This is the technical portion of the RFC. Explain the design in sufficient detail that:
187+
188+
- Its interaction with other features is clear.
189+
- It is reasonably clear how the feature would be implemented.
190+
- Corner cases are dissected by example.
191+
192+
The section should return to the examples given in the previous section, and
193+
explain more fully how the detailed proposal makes those examples work.
194+
-->
195+
196+
# Drawbacks
197+
[drawbacks]: #drawbacks
198+
199+
All drawbacks for attributes in any location also count for this proposal.
200+
201+
Having attributes in many different places of the language complicates its
202+
grammar.
203+
204+
# Rationale and alternatives
205+
[rationale-and-alternatives]: #rationale-and-alternatives
206+
207+
> Why is this design the best in the space of possible designs?
208+
209+
If function parameters can be annotated it is only natural that function return
210+
types can be annotated as well.
211+
212+
> What other designs have been considered and what is the rationale for not choosing them?
213+
214+
Using a function attribute to annotate the return type can result in the
215+
annotation being far apart from the type that it's annotating, as showcased in
216+
the [Motivation](#motivation) section.
217+
218+
[RFC2602](https://github.com/rust-lang/rfcs/pull/2602) suggests permitting
219+
attributes to be attached to any types, so implementing that RFC would also
220+
permit return types to be annotated with attributes. The concern that has
221+
however been raised with that approach is that permitting attributes nearly
222+
everywhere would undesirably increase the cognitive load needed to read Rust
223+
code and thus harm the readability of Rust. Currently attributes are
224+
restricted to specific positions. Allowing them anywhere (even in nested types)
225+
would pose a more radical change, whereas this RFC is more of a continuation of
226+
the status quo by just permitting attributes in one more specific position.
227+
228+
> What is the impact of not doing this?
229+
230+
DSLs cannot take advantage of the additional expressiveness.
231+
232+
# Prior art
233+
[prior-art]: #prior-art
234+
235+
Parameter attributes were introduced to Rust with [RFC2565].
236+
237+
# Unresolved questions
238+
[unresolved-questions]: #unresolved-questions
239+
240+
Are there more built-in attributes that should be permitted for return types?
241+
242+
Is there precedent of other programming languages permitting return type
243+
annotations to be placed directly in front of the return type?
244+
245+
# Future possibilities
246+
[future-possibilities]: #future-possibilities
247+
248+
If `rustdoc` one day supports documentation comments on parameters, it could
249+
also support documentation comments on return types.

0 commit comments

Comments
 (0)