Keys are not stored with mappings. That might seem strange because in JavaScript, Object.keys();
retrieves all the keys, the same is not true with mappings.
With mappings we are working with a classic data structure called a hash table. The hash table uses something called a look up process.
In order to look up some different value from this mapping we have to provide a key ahead of time. We provide this key, it gets passed to a hashing function and the hashing function outputs some pre-determined index.
In a Solidity mapping, keys are not stored. That means we cannot get a list of keys, we cannot access them. We don’t know what keys a mapping has.
The next thing about mappings is that values are not iterable. In other words, we cannot loop through a mapping and print out all the variables that it has.
If we have a mapping we cannot write a for
loop that iterates through all the values. We cannot run any type of function or call that says go into the mapping and retrieve all the values that exist.
Back inside the JavaScript world, we can do that with Object.values();
, but we do not have that functionality inside of Solidity. All we can do is do a lookup.
These mappings are only good for single value lookups. They are not good for storing information that we want to iterate through at some point in the future, but I am not suggesting you go with arrays either as it has its own drawbacks inside the Solidity world that I have answered a couple of times already on this forum.
With Solidity mappings, “all values exist”. Whereas with JavaScript objects if a key has not been defined and we try to access it we get back undefined
.
The same is not true of mappings. In other words, if I look up a key, instead of telling us there is no value at that particular index we actually get returned some default value for that element. If they are strings, then the default value is empty string.
In the JavaScript world, that means that if I tried to look up a key that did not exist, I would not get back undefined
but instead an empty string.
The default value we get back depends on the value type of the values inside of our mapping.
If these were not strings, but say integers then we get back a zero value for an integer which would literally be the number zero.
This makes it challenging to decide whether or not a value exists inside of a mapping. If you are storing numbers inside of a mapping as values and you want to find a value for a certain key and you look up a string and you get back the number zero, that makes it challenging to understand if that value already exists inside the mapping and it was set to zero or no we got back zero because that is a default value based on integers.
Its tough to decide whether or not a value exists ahead of time with mappings.
On the positive side, because mappings has this benefit of constant time look up and we want to ensure our contract can be used with many different contributors.
What is Constant Time?
The big difference between an array and mapping is that doing a search inside of a mapping is what is called in Computer Science discipline, Constant Time.
When we say constant time, it means that no matter how many pieces of data we are storing inside this mapping, its always going to take the same amount of time. This is important when considering that arrays take Linear Time which means whenever we are trying to find some piece of data inside an array, the best case we can get for running that search is Linear Time. When we say that search inside of the array is linear time that means that for every additional record we add to this array, it will take a slightly larger amount of time to execute the search.
That is what is going to get you into trouble with gas prices if you go with arrays instead of mappings.