PhantomRef (or lifetimes without references)?


#1

Would it be possible to have a PhantomRef type that could be used to tie the lifetime of object A to the lifetime of object B without having object A hold a reference to object B? This would allow me to create a struct with one member that must outlive another member. As far as I can tell this isn’t possible now because the only way to ensure object A outlives object B is to have object A hold a reference to object B, but then you couldn’t hold object A and B in the same struct.

This would be very useful when interfacing to a library that has context variables. See this issue for an example.

I’m not familiar with the compiler internals. Would something like this be possible? Or are lifetimes and references too coupled to have one without the other?


#2

Maybe I’m misunderstanding, but could you use PhantomData<&'a T> instead? That’s what I’ve done when writing Rust wrappers for C libraries and need to sprinkle some lifetimes on top.


#3

You can do that, but then there is the unnecessary restriction that a Parent struct and a Child struct that contains a PhantomData<&'a Parent> reference to the Parent can’t live in the same struct. This is because the compiler thinks there is a value and a reference to that value in the same struct, which it tries to prevent. I’m looking for a way to tie two lifetimes together without this restriction.

Here’s an example of what I’m trying to do. The only reason it doesn’t compile is because I’m faking a reference when really all I need is to make sure the Child doesn’t outlive the Parent.


#4

Can you elaborate a bit more on what you’re trying to achieve in your example? Specifically, what do you want to be able to do with Combined? Making Parent: Copy or using struct Combined<'a>(&'a Parent, Child<'a>) allows the code to compile.


#5

Sure. I would like to hold Parent and Child in the same struct. I can’t rely on Parent being Copy, and I want to hold the actual Parent object in the Combined struct, not just a reference (imagine I needed to return the Combined struct from a function).

Here’s a less contrived example, and one I ran into in a project of mine. The libusb::Context definitely shouldn’t be Copy, and the get_device function was a callback from a C library, so I needed to return all state in one struct (then cast to a void *). I think the libusb wrapper library is doing everything right: the Device holds a fake reference to the Context variable to ensure that the device outlives the libusb context. But this also introduces the restriction that a Device and associated Context can’t live in the same struct. In this example, this is an unnecessary restriction because there’s no actual reference.

I’m looking for a way to tell the compiler that one object needs to outlive another, but without using a reference. PhantomData is a way to get some effects of a struct member but not others (you get type-safety and lifetimes but without allocating memory for that member). I’m looking for a PhantomRef which would allow me to get some effects of holding a reference (lifetimes) without others (the value-and-reference-in-the-same-struct restriction).

As far as I know this needs to be provided by the compiler (i.e. PhantomRef can’t be provided by some other crate). I’m wondering if something like this would be easy to implement and if it’s a feature the compiler team would want to expose.


#6

Ah, I understand now. This boils down to supporting internal references, which is not currently possible. See https://stackoverflow.com/questions/32300132/why-cant-i-store-a-value-and-a-reference-to-that-value-in-the-same-struct.


#7

Yeah, that’s the issue I’m running into. In fact, I referenced that stack overflow question earlier in this thread. I’m wondering if it would be possible to support internal references for PhantomData references, since it seems to me that the reasons for forbidding internal references don’t apply to PhantomData references.