100 days of solidity (Day 2–3) pt. 1

100 days of solidity (Day 2–3) pt. 1

Solidity Basics (Solidity Data Types and Operators)

Data types in Solidity can be classified into two categories. They are values and references.

Value Types

Variables of these types will always be passed by value. They are always copied when they are used as function arguments or in assignments. It means the data stores a value; for example, a boolean stores “true or false." Below are the various value types.

Booleans:

bool: The possible values are the constants true and false.

bool a = true;
bool b = false;
bool c = 1 > 2; // evaluates to false

if (a) {
  // do something if a is true
} else if (b) {
  // do something if b is true
} else {
  // do something if neither a nor b is true
}

if (c) {
  // this block of code will not be executed because c is false
}

Above is an example code snippet that demonstrates the use of the bool data type in Solidity:

The operators || and && apply the common short-circuiting rules. This means that in the expression f(x) || g(y), if f(x) evaluates to true, g(y) will not be evaluated even if it may have side-effects.

Integers

int/uint: Signed and unsigned integers of various sizes. Keywords uint8 to uint256 in steps of 8 (unsigned of 8 up to 256 bits) and int8 to int256. Integers in Solidity are restricted to a certain range.

For example;

uint32, this is 0 up to 2**32 - 1

uint8, this is 0 up to 2**8 - 1

uint16, this is 0 up to 2**16 - 1

uint256, this is 0 up to 2**256 - 1

Uint only supports numbers that are greater than zero. If you want to use negative numbers, you can use int. With int, you can use both negative and positive numbers.

Like uint, there are variations to int offering different sizes.

For example;

int256, -2**255 to 2**255 - 1

int128, -2**127 to 2**127 - 1

Memorizing the integer sizes in solidity can be quite difficult. To easily access the minimum and maximum values for an integer type X, you can use type(X).min and type(X).max.

Here's an example code snippet demonstrating the use of these expressions:

uint8 minValue = type(uint8).min; // 0
uint8 maxValue = type(uint8).max; // 255

int256 minValueSigned = type(int256).min; // -2^255
int256 maxValueSigned = type(int256).max; // 2^255-1

Integer operators

  • Comparisons: Comparisons are used to compare two values and evaluate their relationship to each other. <=, <, ==, !=, >=, > (evaluate to bool). Example
uint a = 10;
uint b = 5;

bool lessThanEqual = (a <= b); // evaluates to false
bool lessThan = (a < b); // evaluates to false
bool equalTo = (a == b); // evaluates to false
bool notEqualTo = (a != b); // evaluates to true
bool greaterThanEqual = (a >= b); // evaluates to true
bool greaterThan = (a > b); // evaluates to true

In this example, we compare the values of variables a and b using the comparison operators.

  • Bit operators: &, |, ^ (bitwise exclusive or), ~ (bitwisenegation)

  • Shift operators: << (left shift), >> (right shift)

  • Arithmetic operators:Arithmetic operators are used in computer programming to perform mathematical operations on numerical data types. +, -, unary - (only for signed integers), , /, % (modulo), * (exponentiation)

      uint a = 10;
      uint b = 3;
    
      uint sum = a + b; // 13
      uint difference = a - b; // 7
      int negation = -a; // -10 (note: unary minus is only for signed integers)
      uint product = a * b; // 30
      uint quotient = a / b; // 3
      uint remainder = a % b; // 1
      uint power = a ** b; // 1000
    

    In this example, we have two variables a and b, both of uint data type, and we use the arithmetic operators to perform various mathematical calculations. By default, all arithmetic is checked for under- or overflow, but this can be disabled using the unchecked block, resulting in wrapping arithmetic. Division by zero and modulo with zero causes a Panic error. Unchecked cannot disable this check.

    Note that 0**0 is defined by the EVM as 1.

    Fixed Point Numbers

    Fixed point numbers represent decimal numbers in Solidity, although they aren’t fully supported by the Ethereum virtual machine yet. They can be declared, but cannot be assigned to or from.

    Address

    Addresses come in two identical types. They are

    • The one that holds a 20-byte (the size of an Ethereum address) value, "address," And,

    • The same as the first one, but with the additional members transfer and send, “address payable”.

The address type represents a non-payable Ethereum account address, while the address payable type represents a payable Ethereum account address.

Address payable is an address you can send Ether to, while you are not supposed to send Ether to a plain address, for example, because it might be a smart contract that was not built to accept Ether. You might lose your ether due to this.

Fixed-size byte arrays

The value types bytes1, bytes2, bytes3, . . . , bytes32 hold a sequence of bytes from one to up to 32.

Fixed-size byte arrays operators:

  • Comparisons: <=, <, ==, !=, >=, > (evaluate to bool)

  • Bit operators: &, |, ^ (bitwise exclusive or), ~ (bitwise negation)

  • Shift operators: << (left shift), >> (right shift)

  • Index access: If x is of type bytesI, then x[k] for 0 <= k < I returns the k th byte (read-only).

  • .length yields the fixed length of the byte array (read-only)

    Literals

    This is a data type that can be represented directly by a literal value in the source code, without the need for any variables or expressions.

    • Address Literals: Address literals are a way to represent Ethereum addresses in Solidity code. They are written as hexadecimal values and have a length of 20 bytes.

    • Rational and integer literals: integer literals are whole numbers, while rational literals are numbers with decimal points. Scientific notation in the form of 2e10 is also supported.

    • String Literals and Types: String literals are written with either double or single-quotes ("foo" or 'bar'), and they can also be split into multiple consecutive parts ("foo" "bar" is equivalent to "foobar") which can be helpful when dealing with long strings.

Hexadecimal Literals: Hexadecimal literals are prefixed with the hex keyword. An example of hexadecimal literals is hex"1A2B3F". Hexadecimal literals behave like string literals and have the same convertibility restrictions.

Enum

Enums, short for Enumerable, are user-defined data types in solidity, that restrict the value of the variable to a particular set of constants defined within the program. Enums are useful when you want to define a set of options or choices that a user can select from. For example, you could define an enum for the different types of pets that a user can own in your decentralized application:

    enum PetType {
      CAT,
      DOG,
      FISH,
      BIRD
    }

Contract Types

Every contract defines its own type. You can also instantiate contracts. Contracts do not support any operators. Contracts contain functions that can modify the contract’s state variables. They have no operators.

Function type

Function types are types of functions. Function types can either be internal or external. By default, function types are internal, so the internal keyword can be omitted.

Reference Types

Currently, reference types comprise structs, arrays and mappings. If you use a reference type, you always have to explicitly provide the data area where the type is stored: memory (whose lifetime is limited to an external function call), storage (the location where the state variables are stored, where the lifetime is limited to the lifetime of a contract) or calldata (special data location that contains the function arguments).

  1. Arrays:

    Arrays can be fixed or dynamic. The type of an array of fixed size k and element type P is written as P[k], and that of an array of dynamic size as P[].

  2. Structs

    This is a way to define new types. A struct lets you define a collection of related variables, that can then be used as a single unit. It is a collection of elements of the same data type.

  3. Mapping Types

    They store data in key-value pairs similar to dictionaries in other object-oriented languages, with the key being a value data type, and the value being any type.

Here's an example Solidity contract that demonstrates all the data value types:

contract Datatypes {
    // Boolean
    bool public isTrue = true;

    // integer
    int8 public smallNumber = -128;
    int256 public bigNumber = 2 ** 255 - 1;

    // Unsigned integer
    uint8 public smallUnsignedNumber = 255;
    uint256 public bigUnsignedNumber = 2 ** 256 - 1;

    // Address
    address public myAddress = address(this);

    // String
    string public myString = "Hello, world!";

    // Bytes
    bytes public myBytes = hex"1234567890abcdef";

    // Fixed-point decimal
    //  Note: avoid using fixed-point numbers
    fixed public fixedNumber = 1.5;
    ufixed public ufixedNumber = 0.123;

    // Enum
    enum State {
        Pending,
        Approved,
        Rejected
    }
    State public currentState = State.Pending;

    // Array
    uint256[] public myArray = [1, 2, 3, 4, 5];

    // Mapping
    mapping(address => uint256) public myMapping;

    // Struct
    struct Person {
        string name;
        uint256 age;
    }
    Person public myPerson = Person("Alice", 30);  
}

Okay! That's a good information on data types. We move on to day 3 where we talk about global, state, and local variables.

How are you finding the challenge?

Click here to see the Github repo for this 100 days of solidity challenge.

Click here for guidelines for becoming a Solidity developer.

To learn more about blockchain, click here.

To learn more about Web3, click here.

Follow me for more knowledge on Solidity, Ethereum, and blockchain.