Hi Joseph,
Essentially, yes. It is the EVM which is actually executing a smart contract’s functions, and so when we talk about the different types of data location, we are referring to the different ways the EVM stores the data which is involved in the computations being performed. This can either be temporary storage (in memory
) or persistent/permanent storage (in storage
) depending on how each particular piece of data needs to be utilised…
When a successful function call assigns values to a contract’s state variables (including mappings), this changes the current state of the smart contract. It is this current state which needs to be stored persistently, because this “latest position” is the basis for the computations that follow. You are right that the location for this persistent storage of data is the blockchain, because all changes of state are reflected within the transaction data which is included within its blocks. This ensures that the current state of a smart contract persists between each successive function call, and that all previous changes remain permanently recorded on the Ethereum blockchain.
The first word in a variable definition in Solidity is the data type i.e. uint
, bool
, string
etc.
It only starts with a capital letter in the definition we are referring to…
User memory user = users[id];
…because our data type here is the struct that we have defined with the name User
and not user
. We can define a struct with whatever name we like (within the character constraints provided by the syntax), and so we could use a lower case letter. However, standard practice is to start struct names, event names and contract names with a capital letter (e.g. struct User
, event Withdrawal
, contract Bank
). This is in contrast to variable names (including mappings and arrays), arguments and parameters, which we usually start with a lower case letter. This contrast is in fact of vital importance in our example, because if it wasn’t for this difference, the struct name and variable name would be exactly the same, and this would result in a compiler error.
user
is just the name we have chosen to give to this local variable. We could call it anything that we think would make a suitable identifier (again, within the character constraints provided by the syntax). The variable name user
identifies the variable, and can be used to reference whatever value is currently stored within this variable. In our example, this value is users[id]
which is a reference to a particular key within our mapping. The users
mapping stores instances of the User
struct…
mapping(uint =>
User
) users;
These instances are the ones that are created and assigned to the mapping when the addUser function is called:
users[id] = User(id, balance);
I think I’ve already answered that above.
These concepts can be difficult to grasp and assimilate all at once, so don’t be too hard on yourself during these early stages. Don’t get me wrong, it’s really important to notice these things and try to work out what’s really going on with the syntax, so don’t stop questioning these types of things, and keep turning them over in your mind. But due to the nature of everything being inter-related, things will click into place gradually… trust me… I speak from experience 
Just let me know if you have any further questions 