Oh is Box just a single value? I only looked at Vec in detail and that stores a few different things.

But the code you wrote there isn't the kind of thing I was talking about. Let me try to do a better job explaining. After a bunch of trouble with the borrow checker, here is some code:

#[derive(Debug)]
struct Point {
x: i64,
y: i64,
}
impl Point {
fn new(x: i64, y: i64) -> Self {
Self {
x: x,
y: y,
}
}
}
use rand::Rng;
extern crate alloc;
fn rand() -> u8 {
let mut rng = rand::thread_rng();
rng.gen()
}
fn test() {
let v1;
let v2;
let v3;
let v4;
let n: u8 = rand();
let address;
if n<30 {
v1 = vec![Point::new(2, 3)];
address = &v1 as *const Vec<Point> as usize;
} else if n<60 {
v2 = vec![Point::new(2, 3)];
address = &v2 as *const Vec<Point> as usize;
} else if n<90 {
v3 = vec![Point::new(2, 3)];
address = &v3 as *const Vec<Point> as usize;
} else {
v4 = vec![Point::new(2, 3)];
address = &v4 as *const Vec<Point> as usize;
}
println!("{:#x}", address);
println!("{:p}", &address);
println!("distance: {:#}", (&n as *const u8 as usize) - address);
}

fn main() {
for _ in 0..30 {
test();
}
}

The assembly was annoying to go through so I printed the stack addresses instead. And I used Vec because it's bigger.

This code creates 4 vec variables. It randomly picks one to put a Vec with a Point into, and leaves the other 3 uninitialized.

Then whichever one got initialized has its address stored into "address".

Then it prints out that address, and the address of "n", the next thing on the stack. And it prints out the difference to be extra helpful.

I ran this on the rust playground.

2/3 of the time it uses v4. And 2/3 of the time it prints 31 as the distance.

The rest of the time is evenly split between v1, v2, and v3. And the rest of the outputs are randomly split between 55, 79, and 103.

Therefore I conclude that it allocated space for all four variables at the start of the function, even though there was only one value.

A variable doesn't take up space when the compiler can be clever enough to make it not exist at that moment in time. But that only happens for some code. It's easy to find cases where variables exist as real tangible chunks of memory, even though there aren't values. If you try to touch them, the borrow checker will complain extremely hard.

So here is how I would summarize things: Sometimes the compiler can avoid having variables exist at runtime. Sometimes the compiler can avoid having values exist at runtime. Very often it will reduce the amount of time a variable exists to avoid memory use and to avoid moves and copies. And very often a variable will actually be the final resting place of some value, rather than a default location on the stack. But variables are not just a compile-time concept. They can manifest as chunks of possibly-empty memory when the compiler isn't clever enough or when there's not enough benefit to being clever.

> Above there is an example for this. The Point comes to an existence at some point, while variable p doesn't. So variables do not exist at run time, while values do.

That's not an example of a value not existing at run time. I mean something like setting n=pi*2, then printing n with 2 digits of precision. If the compiler is having a good day, you'll see code that directly prints "6.28" and the value of pi*2 will never exist at run time.

In the most literal sense, neither values nor variables have to exist. Only side-effects exist, and the program could have a completely different implementation from what the source code suggests.