A type such as Box<dyn Capture + '_>
also has a lifetime parameter. The only advantage it has over other types with lifetime parameters is that it can utilize some special elision rules that allow you to write Box<dyn Capture>
as a shorthand for Box<dyn Capture + 'static>
.
As for the code you’re asking about w.r.t. soundness, it looks relatively sound to me, given that user-code will not be allowed to construct arbitrary T
values. I can’t think of a way to implement something like release
soundly without unsafe
, if the requirement is that a Box
is involved and re-allocation should be avoided, as there’s no existing API for re-using an allocation of a Box
while changing the contained type, even if a completely new value is to be assigned and the type change only changes a lifetime.
However, if avoiding the Box
is the goal anyways, then you could just have such API construct a new value and that should not be a problem in safe code. Of course I don’t know your concrete “practical” use-case, so I cannot say for sure how straightforward this would or wouldn’t be.
As for how to solve the problem of using the same type sometimes with and sometimes “without” a lifetime, as hinted at in my first paragraph, all your current solution does is make writing “'static
” a bit simpler, and if you can live without that simplification, the straightforward solution is yet to just use something like Cow<'static, T>
for the owned lifetime-“free” version. (Though if you want to, you can of course use your own enum
, it doesn’t have to be Cow
itself.) If writing the 'static
becomes too tedious, a type alias can help. E.g. type LifetimeFreeCow<T> = Cow<'static, T>;
(good names to be determined).
Of course, this still is a difference at the type level. If you do have a single type Foo<'a>
and use Foo<'static>
for the owned version, then removing any contained references and converting back to Foo<'static>
at the same time will still involve converting e.g. Foo<'a>
to Foo<'static>
which safe code can only do by re-constructing the struct, and thus if the value was also boxed / on the heap, safe code could do this while re-allocating.
This reminds me, I had previously in some answer in this forum also suggested unsafe code for a “comparable” conversion of making a lifetime 'static
safely because all contained references where removed. The use-case was something like Vec<&'a Foo>
which was supposed to be re-used in a loop, and each iteration put new local references into the Vec
, uses it, and then no longer needs the values, but unsafe was necessary to convert the Vec<&'a Foo>
back into Vec<&'static Foo>
after .clean()
-ing the vec, so it could escape the loop body, and be re-used in the next iteration (then variance could convert it back into a shorter-lived Vec<&'a Foo>
again to hold short-lived references). I’d say there might be some general design-work that could be done eventually for coming up with as-general-as-possible safe APIs for re-using allocations (of Vec
or Box
or other things) while (slightly) changing the type, and where the contained values are dropped / removed / cleared / … to make the type conversion sound. Edit: Found the posts about that in case you’re interested; of course it’s only somewhat relevant for this use-case. Also I mis-remembered, the solution didn’t even involve unsafe
code directly but instead relied on specialized implementations for iterators and .collect
on Vec
. Here’s one comment about such a case and it also links another related discussion.