Data Location Assignment [OLD]

I’m going to be honest I got confused by this…remix was throwing up strange errors and wouldn’t let me compile the broken script before I could even try to fix it

The problem is that the updateBalance function does not consolidate the new balance in to the users mapping (which has a storage type data allocation). The User memory user = users[id]; has a memory type data allocation, and it will only be valid during the updateBalance function execution.

We could just update the balance directly changing the mapping value:

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

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

It took me forever to come up with the solution. I tried several different solutions while keeping the “memory” location in the code. Once I realized I should change the location to “storage”, the answer came easily!

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

Hi @ponchooo,

Are you still having problems? If so, what code are you trying to compile as your solution, and what errors exactly is the compiler throwing? We need to know that in order to help you.

Have you compared your code to other students’ solutions posted here? Maybe that will help you come unstuck…

Anyway, let us know how you’re getting on.

1 Like

I was able to fix it in a couple of different ways. I like the second solution better because it’s just working directly with the mapping data.

Question: Does putting the user into memory and modifying it there cost more gas? If it does then I definitely like option 2 better.

I see others are using storage instead of memory. Interesting… It seems to me that the users mapping is already in storage and thus that specific user. Isn’t that just creating a copy that you don’t really need and might that cost more gas?

OK - Filip just explained that it’s a pointer to the same object.

1 Like

First thing that came to my mind is to change data location type in updateBalance function from memory to storage. Since the memory type data allocation stores the variable value only during function execution, all variables outside function scope remain unchanged once the function is executed. Other logical and little bit more elegant solution is to lose intermediary step and directly use mapping in updateBalance function instead, which uses storage data allocation by default users[id].balance = balance; but this was not mine solution…

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 {
     User storage user = users[id];
     user.balance = balance;
}

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

}

1 Like

Hi @chadrickm,

That’s good that you’re experimenting with different alternative solutions, and even better that you’re also considering potential gas implications :+1:

Yes it does:

Option 1 is more expensive: total gas = 1985 (1045 with optimization turned on)

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

Option 2 is cheaper: total gas = 99 (78 with optimization turned on)

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

Setting the data location to storge instead of memory

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

// costs ever so slighty more gas than Option 2 (with optimization turned off)
// but costs exactly the same with optimization turned on, which makes sense
// total gas = 115 (78 with optimization turned on)
1 Like

Just needed this change…

   function updateBalance(uint id, uint balance) public {
         User storage user = users[id];
         user.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
function updateBalance(uint id, uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}

or simply

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 { // update balance when deploying contract doesn't work
     User storage user = users[id]; // simple solution was change the "memory" to "storage". It didn't work before because memory is temporary where storage is permanent same as mapping. "Memory" was executed once and deleted that's why there was no value to change via updateBalance function. 
     user.balance = balance;
}

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;
}

changing memory to storage works but is very confusing.
Changing it directly seems better.

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 {
     users[id].balance = balance
}

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

}

1 Like

pragma solidity 0.5.12;

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

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
pragma solidity 0.5.12;

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].balance = user.balance;
    }
    
    function getBalace(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;
	boolean state = false;     //  added #1
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance, true); 		 //  added #2
}

function updateBalance(uint id, uint balance) public {
    if(  users[id].state == true ){			     //  added #3
		users[id].balance = balance;
	}				
}

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

}

1 Like

This is wat I did:

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