Solidity Basics

Hi Gabba

I got it to work. it’s a , as apposed to . Thanks anyway.

Steve

Your address in the Remix IDE has run out of Ether would be my guess. When you refresh the Remix page it reloads addresses and they each get their 100 ETH, so you have gas again.

Thanks Petra :slight_smile:

1 Like

You are very welcome.

I accidentally deployed a contract from a zero eth addy somehow interfacing with Metamask/Ropstein and couldn’t interact with it and had to start over… Argh!

Pretty sure it gives you all new addresses too when you reload, so you’ll have to change addresses in your contracts as well or they’ll use the old versions. I’m not sure how persistent the Remix blockchain is though…

Now I’m thinking I need to test that.

2 Likes

In the If & Else - Control Flow I would have at least mentioned the ternary operator:

https://solidity.readthedocs.io/en/v0.4.21/miscellaneous.html

14 Ternary operator <conditional> ? <if-true> : <if-false>

I mean for such a basic setter or an object property, the ternary operator is more suitable:

newPerson.senior = (age > 65) ? true : false;

I prefer to use if/else for more complex operations.

One of the first things I check in a new programming language is the existance of the ternar operator. If it exists it should be used where suitable :wink:

2 Likes

Yes i agree with you @firepol ternary operator are more ‘sexy’.

But as you can see in this discussion with @jon_m it seems that it cost more gas to execute, i was really surprised (he had run his tests without the optimization on)

https://forumtest.ivanontech.com/t/integer-types-createperson-function-alternatives-gas-optimization-view-v-pure-functions-non-iterable-nature-of-mappings-by-jon-m/12169/8

Ternary operator (highest gas cost = 80)
if…else statement (gas cost = 67)
Boolean expression assigned directly (lowest gas cost = 52)

1 Like

Hey @gabba, thanks for the answer. Interesting that the compiler makes such a difference. I mean I thought that code that does the same thing can actually be compiled more efficiently, regardless on how it is written. Wow.

So in the end my code can be optimized further like so newPerson.senior = age > 65; and it is the cheapest way to spare gas. Nice.

I’m really surprised that the compiler doesn’t compile

newPerson.senior = (age > 65) ? true : false;

in the same way as

newPerson.senior = age > 65;

because this code does exactly the same thing (it’s just written a bit “longer”, and if you use if else, even longer but it does the same thing). Why on earth it has a higher cost in gas?!

Yeah i was really surprised too … @jon_m ran this test i should probably test it. Looking at the debugger will help to know which instructions are being used. I think useless op codes are used there.
Doing the same test with optimization enable should output the same amount of gas, because yeah this is the same thing ! :exploding_head:

I did test this myelf (right now) and it’s really true, in my code the execution of

newPerson.senior = (age > 65) ? true : false;
costed: 7001 gas

newPerson.senior = age > 65;
costed: 6973 gas

Wow, mindblowing! Anyway, discussing here made me realize that it’s kinda stupid (not sexy) to use the ternary operator as I wrote. I mean this is the most “sexy” variant: newPerson.senior = age > 65; and I’m happy that it’s also the one that uses less gas :wink:

2 Likes

@gabba

Hey @firepol !

I think we need to be clear about what we mean by efficiency. I totally agree with you that a ternary operator is more compact and concise than an if…else statement. And I think in JavaScript it can often be considered more efficient and cleaner code. However, in Solidity we need to consider gas cost, and this is based on the number and type of operations. Having experimented with this, it’s clear to me that shorter doesn’t necessarily mean cheaper.

If you haven’t already done so, when calling the createPerson function with each of the different control flow statements, click on Debug next to the transaction detail (bottom right) to open the Debugger. You can click forward through the different operations contained within the createPerson function until you get to the first one associated with the control flow statement you are testing (you will know as the associated code is highlighted). As you then click through all the operations associated with that particular piece of code, you will notice the different amounts of gas used for each operation. I basically added up all the amounts for each different control flow statement and compared the totals.

I was interested to see that you used the ternary operator differently to me:

My version:
age >= 65 ? newPerson.senior = true : newPerson.senior = false;

So, I’ve tested your ternary operator as well, and with optimization OFF, the gas is the same as with my ternary operator (80), and only 2 less than mine with optimization ON (73 instead of 75).

It’s also worth bearing in mind that in your ternary operator, the  ? true : false  part is actually redundant, because the expression   age >= 65  will return true or false anyway. So just as you’ve already realised, the prize for Sexiest Control Flow Statement (or at least Cheapest) goes to…

:partying_face:

And thanks, because looking in more detail at your version of the ternary operator has made me realise that in the end newPerson.senior = age >= 65; is actually a condensed form of my ternary operator as well! :smiley:

1 Like

@firepol

Actually not! With optimization ON, there is still no difference in the order from most gas (ternary operator) → least gas (boolean expression assigned directly). In fact the difference between the amounts of gas used is actually greater; so, relatively speaking, the ternary operator is even more expensive than the others when optimization is enabled.

You can see my results here.

2 Likes

I still don’t get the difference between mapping and arrays.
Filip in his ethereum solidity mapping video explained how to do mapping, but it looks like inputing information same way like he did with array with the exception of making it private. Please advice and apologies if I am lost.

@jon_m
Many thanks for your explanation. You explained it way better than other sources I have been reading. I am a beginner in terms of mapping. I hope you don’t mind getting back to you in the future should I get stuck with anything.
Sincerely,

1 Like

Hi,
I followed Fillip’s mapping video till the end. I created the code, compiled it (no errors) and deployed it. I still don’t know how to use this way to do mapping though:

people.push (Person (people.length, name, height, age))

He showed it in the previous video before mapping, but did not explain how to continue using it since it looks easier.

1 Like

Filip, I believe that there is a little mistake at the beginning of the video where you describe an unsigned integer (of type uint) as one that can be both positive and negative. It seems to me that “unsigned” means that there is no sign. So unsigned integers, by definition, are greater than or equal to zero. To confirm this, I tried assigning a negative value to a uint variable, and, as expected, the compiler produced a corresponding error message.

1 Like

@filip

Hey, can you tell me why I keep getting a compiling error on the code that I am doing from video 4 on struct please? I have attached a screen shot :slight_smile:

Hi @TommyBrook,

I’m glad that explanation helped. You may have noticed that I removed my original reply. That’s because I needed to correct it for one inaccuracy that I realised afterwards. So I’m reposting a new improved version, here, now (see below). Basically, I said mappings don’t store the actual values, but actually they do — they just store them in a different way to arrays. Everything else about the explanation and analogy is broadly correct, at least to get a basic understanding of the differences between mappings and arrays. Please, be aware that this explanaation is oversimplified, but that’s often what we need when we first try to understand these concepts. Then it becomes a journey of discovery, where you will gradually realise the finer details for yourself, over time. At least this is a start…

The other thing I’m updating the explanation for, is the fact that arrays store their values based on a sequence of indices. So the key/value pairs are effectively index/value pairs. With mappings, there is no order to the values, just key/value pairs (e.g. address/value), so you need to provide the specific key that is mapped to the value, in order to access it.

Anyway, here’s the updated explanation:

Think of an array as being like a filing system/cabinet. You can search around in it, retrieve data from specific places in it, and you can iterate over it. All of the values stored in an array are like the contents/data in each of the files in a filing cabinet. These values (file contents) are ordered according to a sequence of indices (0, 1, 2, 3 etc.), a bit like filing reference numbers. Each index (file reference number) and it’s associated value (file contents/data) is a key/value pair (the key being the index).

A mapping is more like a telephone operator (bear with me…). If you give it a key (whatever the key has been defined as — let’s say a telephone number for this analogy, but in Solidity it’s more likely to be an address)… with that key (telephone number) the mapping will supply you with the value that the key is mapped to (the telephone operator will connect you to the person who is “mapped” to the telephone number you gave them).

The telephone operator (mapping) can only connect you to the other person (return the value) if you already have their telephone number (key/address). With a filing cabinet (array) you can hunt around (manipulate it / iterate over it etc.) until you find what you’re looking for, because of its ordered sequence of reference numbers (indices). Generally speaking, you can’t iterate over a mapping due to it’s non-sequential nature. However, if you have the key to a value (the telephone number of the person you want to speak to and interact with) the mapping (telephone operator) can “put you through” straight away. If you have very large mappings this will save you a noticeable amount of gas (as opposed to using an array). The advantage of an array is its flexibility, whereas a mapping will give you more privacy (you don’t have to speak to a load of other people until you find the one you actually want to talk to).

Wow! That’s a lot longer than the first draft! But it’s more accurate and will hopefully be of help to other Solidity beginners too. I hope, as well, that’s it’s enhanced your understanding, and not caused a slip back into confusion.

Let me know what you think.

I’m going to look at, and answer, your other question now. Thanks for your patience and for bearing with me.

Not at all! That’s what we’re here for :slightly_smiling_face:

1 Like

Hi @TommyBrook,

I think this will answer your question:

struct Person {
   string name;
   uint age;
   uint height;
}

mapping(address => Person) private people;

/* Filip's version of the createPerson function, in the Mappings video
  (based on Alternative 2 in the previous video, when using an array) */
function createPerson(string memory name, uint age, uint height) public {
   address creator = msg.sender;   

   Person memory newPerson;
   newPerson.name = name;
   newPerson.age = age;
   newPerson.height = height;

   people[creator] = newPerson;
}
/* Alternative version of createPerson function, not shown in the Mappings video
   (based on Alternative 1 in the previous video, when using an array) */
function createPerson(string memory name, uint age, uint height) public {
   address creator = msg.sender;
   people[creator] = Person(name, age, height);
}
1 Like

Hi Frank,

Yes, you are correct :+1:

As you say…

uint positiveNumber = 5;

uint negativeNumber = -5;      // => compiler throws an error

(i) uint only allows zero and positive integers up to a max based on the binary places included in the type.
    e.g. uint4 (0 to 15) , uint8 (0 to 255) , uint16 (0 to 65535)

(ii) int allows positive and negative integers from a min of minus(-) half the max based on the binary places included in the type, to a max of plus(+) half the max based on the binary places, and including zero.
    e.g. int4 (-8 to 7) , int8 (-128 to 127) , int16 (-32768 to 32767)

We should always keep within the restrictions in terms of the range of integers available with a given integer type (signed or unsigned), because the compiler will not always prevent an overflow (a loop from the max limit, back to the min limit) or an underflow (a loop from the min limit back to the max limit).

1 Like

Hello sir, after the people.push, look at the last parameter (“height”), you should not have a comma at the end of the last parameter.

If you have any doubt, please let us know so we can help you!

Carlos Z.

1 Like