Return reference from nowhere on a "never" type

I'm writting an API that have a trait that looks like this :

trait BorrowData<Data> {
    fn borrow_data(&mut self) -> &mut Data;
}

I want to implement this trait for a struct from another crate, but I what to signal there is no data to borrow. For that I use a zero size type, but it's seems not possible to create a reference from nowhere.

impl BorrowData<()> for StructFromAnotherCrate {
    fn borrow_data(&mut self) -> &mut () {
        // What here ?
    }
}

Is it possible with static type to represent the "there is not data" ?
Is it actually unsafe to have a referece to nowhere on a ZST since it's not possible to read from or write into ?

To answer your immediate question, this would work:

fn borrow_data(&mut self) -> &mut () {
    &mut ()
}

Through promotion, we create a constant value () and take its address, yielding a &'static mut (). From there, the lifetime can be shortened to the lifetime of &mut self.

However, the design of the BorrowData trait seems odd, especially the use of BorrowData<()> for "there is no data to borrow". How do you anticipate the trait being used?

EDIT: I forgot that promotion only works for immutable references. This is not safely possible for mutable references.

It does work:

error[E0515]: cannot return reference to temporary value
2 |     &mut ()
  |     ^^^^^--
  |     |    |
  |     |    temporary value created here
  |     returns a reference to data owned by the current function

I have some method that borrow the struct and takes a callback that received the borrowed data.

fn foo<T, Data, F>(foo: &mut T, f: F)
where
    T: BorrowData<Data>,
    F: FnMut(&mut Data)
{ ... }

For &mut T (as opposed to &T), constant promotion is special cased for arrays of length 0:

fn works<T>() -> &'static mut [T] {
    &mut []
}

But not for anything else as far as I know, although it could be for ZSTs.

You could do this:
static mut UNIT: () = ();
fn works() -> &'static mut () {
    // SAFETY: `()` is zero-sized and thus cannot alias any memory
    unsafe { &mut UNIT }
}

At least until static mut gets deprecated in a few years maybe :sweat_smile:, in which case you could static-promote an empty array and use unsafe to cast it to a &mut ZST instead.

Edit: But nah, if you have alloc there's a non-unsafe way, see the quoted portion below.

One Google search later, here's a fun approach posted by @Yandros

4 Likes

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.