Skip to content

Commit 3f6faf0

Browse files
adamreicholddavidhewitt
authored andcommitted
Extend guide on interaction between method receivers and lifetime elision. (#4069)
1 parent 4e13c0e commit 3f6faf0

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

guide/src/class.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,44 @@ impl MyClass {
998998
Note that `text_signature` on `#[new]` is not compatible with compilation in
999999
`abi3` mode until Python 3.10 or greater.
10001000

1001+
### Method receivers and lifetime elision
1002+
1003+
PyO3 supports writing instance methods using the normal method receivers for shared `&self` and unique `&mut self` references. This interacts with [lifetime elision][lifetime-elision] insofar as the lifetime of a such a receiver is assigned to all elided output lifetime parameters.
1004+
1005+
This is a good default for general Rust code where return values are more likely to borrow from the receiver than from the other arguments, if they contain any lifetimes at all. However, when returning bound references `Bound<'py, T>` in PyO3-based code, the GIL lifetime `'py` should usually be derived from a GIL token `py: Python<'py>` passed as an argument instead of the receiver.
1006+
1007+
Specifically, signatures like
1008+
1009+
```rust,ignore
1010+
fn frobnicate(&self, py: Python) -> Bound<Foo>;
1011+
```
1012+
1013+
will not work as they are inferred as
1014+
1015+
```rust,ignore
1016+
fn frobnicate<'a, 'py>(&'a self, py: Python<'py>) -> Bound<'a, Foo>;
1017+
```
1018+
1019+
instead of the intended
1020+
1021+
```rust,ignore
1022+
fn frobnicate<'a, 'py>(&'a self, py: Python<'py>) -> Bound<'py, Foo>;
1023+
```
1024+
1025+
and should usually be written as
1026+
1027+
```rust,ignore
1028+
fn frobnicate<'py>(&self, py: Python<'py>) -> Bound<'py, Foo>;
1029+
```
1030+
1031+
The same problem does not exist for `#[pyfunction]`s as the special case for receiver lifetimes does not apply and indeed a signature like
1032+
1033+
```rust,ignore
1034+
fn frobnicate(bar: &Bar, py: Python) -> Bound<Foo>;
1035+
```
1036+
1037+
will yield compiler error [E0106 "missing lifetime specifier"][compiler-error-e0106].
1038+
10011039
## `#[pyclass]` enums
10021040

10031041
Enum support in PyO3 comes in two flavors, depending on what kind of variants the enum has: simple and complex.
@@ -1329,3 +1367,6 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
13291367
[classattr]: https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables
13301368

13311369
[`multiple-pymethods`]: features.md#multiple-pymethods
1370+
1371+
[lifetime-elision]: https://doc.rust-lang.org/reference/lifetime-elision.html
1372+
[compiler-error-e0106]: https://doc.rust-lang.org/error_codes/E0106.html

0 commit comments

Comments
 (0)