From the docs:
constant for state variables: Disallows assignment (except initialisation), does not occupy storage slot.
Does this mean that the EVM caches constants across all contracts using some sort of DHT or sparse Merkle tree?
I think that it is more easy that constant
storage variables are simply put in the compiled code (as in conventional languages with MACROs or CONSTANTS), indeed each occurence and its value is known in advance, so it is possible to put in the compiled code the instruction PUSH <constant-value>
whenever is needed. It would cost few gas units, 3 and only on demand!
You don't have to believe me, you can try with a simple example (with REMIX IDE):
pragma solidity ^0.4.24;
contract C {
uint8 constant x = 137;
uint y;
constructor () public {
y = 1 + x;
}
}
If you check in the compiled code (and in particular in the assembly part) you will note a PUSH 137
instruction (you can change the value of the constant and see that the instruction changes accordingly).
Constant status variables (i.e. constants!) should be known at compile time, so examples like this:
uint8 constant x;
constructor (uint _x) public {
x = _x;
}
simply do not work (I tested it in v. 0.4.24).
The same holds for less dangerous examples (that theoretically should work), like the following one:
uint8 constant x;
constructor () public {
x = 5;
}