::with_locals
Let's start with a basic example: returning / yielding a format_args
local.
The above becomes:
f: F
, here, is called a continuation:
instead of having a function return / yield some element / object,
the function takes, instead, the "logic" of what the caller would have liked
to do with that element (once it would have received it), so that it is the
callee who handles that object instead.
By shifting the logic like so, it is the callee and not the caller who runs that logic, which thus happens before the callee returns, cleaning its locals and making things that refer to it dangle.
This is the whole point of all this strategy!
Now, to call / use the above function, one can no longer bind the "result"
of that function to a variable using a let
binding, since that mechanism
is reserved for actual returns, and the actual code running in the caller's
stack.
Instead, one calls / uses that with_hex
function using
closure / callback syntax:
with_hex
This is extremely powerful, but incurs in a rightward drift everytime such a binding is created:
with_hex
Instead, it would be nice if the compiler / the language provided a way
for let
bindings to magically perform that transformation:
let one = hex;
let two = hex;
let three = hex;
Operating in this fashion is called Continuation-Passing Style, and cannot be done implicitly in Rust. But that doesn't mean one cannot get sugar for it.
Enters #[with]
!
let one = hex;
let two = hex;
let three = hex;
When applied to a function, it will tranform all its so-annotated
let
bindings into nested closure calls, where all the statements that
follow the binding (within the same scope) are moved into the
continuation.
Here is an example:
The above becomes:
let s: String = ;
assert_eq!;
Traits can have #[with]
-annotated methods too.
Example of a user of of the trait (≠ an implementor).
// (Using a newtype to avoid coherence issues)
;
Example of an implementor:
See examples/main.rs
for more detailed examples within a runnable file.