How to name lifetimes for Self?

First and foremost, I’m genuinely opposed to naming lifetimes like ’a and ’b, since those names are non-descriptive.

I am currently implementing an API to interact with Mender servers. Within the crate I have traits for the several endpoints like this:

/// Deployments management API.
pub trait Deployments<'this> {
    /// List deployments.
    fn list(
        self,
        page_size: Option<NonZero<usize>>,
    ) -> PageIterator<'this, 'static, ListDeployment>;

    /// Create a new deployment.
    fn create(
        self,
        deployment: &NewDeployment,
    ) -> impl Future<Output = reqwest::Result<String>> + Send;

    /// Collect deployments into a `Vec`.
    fn collect(
        self,
        page_size: Option<NonZero<usize>>,
    ) -> impl Future<Output = reqwest::Result<Vec<ListDeployment>>> + Send;
}

impl<'session> Deployments<'session> for &'session Session {
    fn list(
        self,
        page_size: Option<NonZero<usize>>,
    ) -> PageIterator<'session, 'static, ListDeployment> {
        Pager::new(self, PATH, page_size.unwrap_or(DEFAULT_PAGE_SIZE)).into()
    }

    async fn create(self, deployment: &NewDeployment) -> reqwest::Result<String> {
        self.client()
            .post(self.format_url(PATH, None))
            .bearer_auth(self.bearer_token())
            .json(deployment)
            .send()
            .await?
            .error_for_status()?
            .text()
            .await
    }

    async fn collect(
        self,
        page_size: Option<NonZero<usize>>,
    ) -> reqwest::Result<Vec<ListDeployment>> {
        Pager::new(self, PATH, page_size.unwrap_or(DEFAULT_PAGE_SIZE))
            .collect()
            .await
    }
}

I really struggled with naming the lifetime for pub trait Deployments<'this>, since my first attempt was to use ’self, which the language unfortunately forbids.

Is there a common guideline to naming lifetimes that represent the lifetime of the trait’s implementor?

this is often used. You could also make it domain-specific like deployment or shared_api.

You're using self in the methods instead of &self. If you used &self then this lifetime would be implied and you wouldn't need to name it.

4 Likes

Thanks for the confirmation. I cannot use &self in the trait method signatures, since I also use those as opaque types to proxy endpoint views.

If I’d not use the explicit lifetimes, but just the ones from the method’s implied borrow of &self I’d get errors à la:

error[E0716]: temporary value dropped while borrowed
  --> prototype/src/main.rs:88:36
   |
88 |                 let mut releases = session.releases().list(None);
   |                                    ^^^^^^^^^^^^^^^^^^           - temporary value is freed at the end of this statement
   |                                    |
   |                                    creates a temporary value which is freed while still in use
89 |
90 |                 while let Some(release) = releases.next().await {
   |                                           -------- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

For more information about this error, try `rustc --explain E0716`

This is because PageIterator is an async lending iterator that need to borrow &Session for its entire lifetime.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.