Skip to content

Commit db61b4a

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

File tree

1 file changed

+248
-0
lines changed

1 file changed

+248
-0
lines changed

text/3201-return-type-attrs.md

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

0 commit comments

Comments
 (0)