Frankly for that type of extremely constrained scenario there's a lot of tools that don't work. I'm not expecting to be able to easily allow ultra-fine-grained control like that. Now, you can imagine ways to specify it, like having different lifetime specifiers for different destinations, passing multiple "scratchpad" pointers to the function, etc. But in general I think for a situation that constrained you probably need explicit out arguments.
When I used to do microcontroller stuff I'd find myself often looking at the raw ASM verifying that the compiler actually did what I expected. 
Yes. Those are toy examples, not meant to illustrate actual problems.
I think the bigger question is actually how useful is this if &own
references are implemented? Because in a lot of cases it'd probably suffice to start with an actual caller provided, object, and manipulate it. Not how my original example with Pin
at the very top would actually worked quite nicely if you could pass it an owning reference.
I mean, returning a value from f2
to f1
's caller can only happen once. So sounds like you're just overwriting a value repeatedly. There'd be some complexity in exactly when to call drop. But that's why in my examples above, I explicitly had functions returning &own
references to make the logic clear, even though that's not actually needed.
I'd expect g2
to "break the chain" and allocate separate scratchpad space for the g2
call from its own stack space. Which would of course happen once per loop iteration.
I think any circumstance where you really need that careful control not only are you going to want to do this explicitly, you're also going to need compiler tooling to verify what stack frames might actually be generated. IIRC Rust does have that now in some form.
Note that an &out
reference can be handled by a method on &own MaybeUninit<T>
, especially if it gets support for unsized types. Eg you could imagine:
impl<T: ?Sized> MaybeUninit<T> {
fn initialize(this: &own Self, value: &own T) -> &own T;
}
Getting a bit off topic, but implicit conversion from passing a T
value to &own T
would be really nice...
I think that definitely might have value. Though need to justify it against return arguments. Also, note how you might want to use super
in destructuring:
let (super [u8; 100], [u8; 1000]) = make_pair();
Could lead to some surprising copying . But interesting to think about at least.