Data Location Assignment [OLD]

image

Perhaps not the most elegant solution, but the most obvious.

1 Like

Instead of instantiating a copy of the user to a local memory variable, I modified to code to update the user’s balance directly on the state variable users.

Before:

    function updateBalance(uint id, uint balance) public {
         User memory user = users[id];
         user.balance = balance;
    }

After:

    function updateBalance(uint id, uint balance) public {
         users[id].balance = balance;
    }
1 Like

I would change the update function as follows:

function updateBalance(uint id, uint balance) public {
    users[id].balance = balance;
}

So that we update the actual balance in storage and not just temporarily within he function.

1 Like

Updates the users mapping with the user as the last line in updateBalance

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {
     User memory user = users[id];
     user.balance = balance;
     users[id] = user;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

1 Like

Simply change the existing ‘memory’ to ’storage’ in the updateBalance function. It may cost more gas, but will function correctly.

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

1 Like
function updateBalance(uint id, uint balance) public {
     users[id].balance = balance;
}
1 Like

Hi All.
I have got 3 solutions as follows in order from the most expensive to the cheapest (gas consumption).

solution-1 (using storage)

contract MemoryAndStorage {
    ...

    function updateBalance(uint id, uint balance) public {
         User storage user = users[id];     // assigns pointer to user, data location is storage. Changing user will change user[id] as well
         user.balance = balance;
    }

    ...
}

solution-2 (using memory)

contract MemoryAndStorage {
    ...

    function updateBalance(uint id, uint balance) public {
         User memory user = users[id];
         user.balance = balance;
         user[id] = user;
    }

    ...
}

solution-3 (directly assign)

contract MemoryAndStorage {
    ...

    function updateBalance(uint id, uint balance) public {
         user[id].balance = balance;
    }

    ...
}
1 Like

Sup, easy to fix just swapped the memory for storage.

pragma solidity 0.5.1;

contract MemoryAndStorage {

mapping(uint => User) users;

struct User {
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

1 Like

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance( uint id, uint balance) public {
     users[id].balance = balance;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

1 Like

As far as I can see original function is needlessly creating a local in memory copy of user struct state variable (for the given index) and then the balance update operation is operating on this copy and hence not changing the state of the underlying account stored as a state variable.

As soon as the code is loaded (At least for me) a warning suggests that the view restriction should be added to the function. This is ONLY suggested as no changes are made to state, hence adding the view restriction is appropriate. This alone is a red flag indicating the function is essentially read-only making no changes to data stored on chain.

Therefore I simply modified the function so that it directly modifies the struct state variable.

function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}

1 Like

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}
1 Like

To solve the problem instead of creating a user in memory:

function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
}

We can use the iput data to operate directly on the mapping entry:

function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}

1 Like

I just commented out the two lines in updateBalance and added “users[id].balance = balance”:
pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {
     //Original code: User memory user = users[id];
     //Original code: user.balance = balance;
     users[id].balance = balance;
}

function getBalance(uint id) public view returns (uint) {
    return users[id].balance;
}

}

1 Like

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
   User memory newUser;
   newUser.id=id;
   newUser.balance=balance;
   users[id]=newUser;
   
}

function updateBalance(uint id, uint balance) public {
     users[id].balance=balance;
     
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

1 Like

Hi @filip

I have a question.
In the data location assignment, I was a bit not sure the difference between these two.
1: User storage user = user[id];
2: User memory user = user[id];

I thought data location is about where you store the data but in the lecture it was said that to point out the right data.
So does that mean 1 is pointing to the data stored in the permanent data location and the other is creating a new one?
If this understanding is correct, I thought the 2nd one will through an error since the user array is not declared. And to create a new element for the mapping you need to input the balance at the same time.

1 Like

Almost got it my friend, Storage you can think has RAM, you will not save the values in the blockchain, you will create a memory space to save for moments your values, but it will not be recorded in the blockchain.

While Memory will save the values in the blockchain, meaning will cost more for the transaction, also is unnecessary space if that variable just need to be used for an internal operation of a function and then it should be deleted or reset.

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.

1 Like

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

1 Like
pragma solidity 0.5.1;
contract MemoryAndStorage {

    mapping(uint => User) users; // Create a mapping where an unsigned integer is a key that maps to a struct "User" that contains the id and a balance. 

    struct User{
        uint id;
        uint balance;
    }

    function addUser(uint id, uint balance) public { //Takes id and balance as inputs, maps given id to a struct that contains that id and the given balances inside the mapping 'users'. 
        users[id] = User(id, balance);
    }

    function updateBalance(uint id, uint balance) public {
         // User memory user = users[id]; //This doesn't interact with state variables, i.e. the original struct in any way; 
         // it just creates a new struct inside this function that will be discarded once the function has finished running. 
         
         users[id].balance = balance; // This seems to work. 
    }

    function getBalance(uint id) view public returns (uint) {
        return users[id].balance;
    }

}
1 Like
function updateBalance(uint id , uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}

Took me some time to figure out that there is a key word ‘storage’ :slight_smile:

Then I saw in the answers that there is also another solution. Any reason to pick one over the other?

1 Like

Depend on what kind of variable you need to just save, update, create a new one, in terms of GAS price of the transaction.

This student share a good answer to understand a little bit the difference in code terms.

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.