0

Solidity: Variables, Modifiers and Types.

Here we will discuss about the different kinds of variables and types that can be utilized within Solidity to develop smart contracts. First we will take a look at how variables are declared and what are the different kinds of variables available, we will then look into access modifiers for variables (which defines their visibility and work very similar as they do in the most common object oriented languages). We will also cover the different types supported by the language and how they can be used.

Finally, we will cover the language-specific type known as address which is widely used, every account and every smart contract within the blockchain has it’s own and unique address that is used to move funds (in the case of accounts) or to identify the contract in order to interact with it.



Variable declaration

The basic format of a variable declaration is as follows:

<type> <access modifier> <name>


Types of Variables

There are three types of variables: state variables, local variables and global variables.

State Variables: State variables are declared in the contract and outside of the scope of any function, they are permanently stored within the contract storage. You can think of them as global variables in the context of the contract and they are used for data storage. In the below example, the variable fooVar is a state variable.

contract fooContract {
    uint256 public fooVar;
}

Local Variables: Local variables are declared within the scope of a function and are accessible only in the context of said function. You can think of them as local variables used for temporary values and their value is not maintained between function calls. In the below example, the variable fooVar is a local variable within the scope of fooFunction.

function fooFunction() {
    uint256 fooVar = 7;
}

Global Variables: These are special variables related to the details pertaining to the transaction and the blockchain itself. Some of these are:

block.numberThe number of the current block.
block.timestampTimestamp of the current block in Unix epoc.
block.gaslimitThe gas limit of the current block.
block.coinbaseThe address of the miner of the current block.
msg.dataThe calldata where function parameters are stored.
msg.valueThe amount of wei sent to a contract.
msg.senderThe sender of the message (current caller).
msg.sigThe function identifier in the calldata.
nowTimestamp of the current block.
tx.gaspriceThe price of the gas for the current transaction.
tx.originThe sender of the current transaction.

Access Modifiers

Access modifiers allows the programmer to define the level of accessibility of a variable or a function (more on functions later on). Modifier can be used to restrict the visibility of the variable as well as to control who can access the it’s value.

There are four basic access modifiers:

Public: Anyone can access the value of the variable.

contract fooContract {
    uint256 public publicVar;
}

External: Only external functions can access the value.

contract fooContract {
    uint256 external externalVar;
}

Internal: Only functions within the contract (and related contracts) can access the value.

contract fooContract {
    uint256 internal internalVar;
}

Private: Only functions within the same contract can access the value.

contract fooContract {
    uint256 private privateVar;
}


Types

In Solidity, types are divided in two big categories: value types and reference types.

Value Types

A value type holds the data in it’s own memory allocation. They are always passed by value and are copied whenever they are used as function parameters or in assignments.

Boolean: Can hold only one of two possible values (or states): true or false.

contract fooContract {
    bool public flag = true; 
}

Integer: Can hold any integer number within the bounds of the type. For example, type uint8 can hold numbers from 0-255.

contract fooContract {
    uint8 private number = 255; 
}

Address: This is a 20-byte hexadecimal value that represents an Ethereum account in the blockchain. You can get the balance of an address or use it to transfer ether to another address.

contract fooContract {
        address owner = msg.sender;
}

Fixed byte array: This is a sequence of a fixed numbers of bytes. From 1 to 32 bytes depending on the type: bytes1, bytes2, bytes3, …, bytes32.

contract fooContract {
    bytes3 public nick = "tux";
}

Dynamic byte array: This is a sequence of dynamically allocated bytes. This includes bytes (dynamic byte array) and string (dynamic UTF-8 encoded string).

contract fooContract {
    string public nick = "tux";
}

Contract: Every contract defines it’s own type (similar to classes in OO programming). You can declare a variable of the type of the contract.

contract fooContract {
    string public nick = "tux";
}

contract otherFoo {
    fooContract public fooCont;
    string nick = fooCont.nick();
}

Enums: An enums is an user-defined type that consists of a fixed number of named values.

contract fooContract {
    enum fooEnum { DEFAULT, ONE, TWO }
    fooEnum val = fooEnum.DEFAULT;
}

Function: This is the type of a function. Function types can be assigned from functions and if they are passed as function parameters they can be used to pass and return functions.

contract fooContract {
    function (uint) internal pure returns (bool) fooFunc;
    
    function fooFunction (uint) internal pure returns (bool) {
       return true;
    }
    
    function otherFooFunction() public {
        fooFunc = fooFunction;
    }
}


Reference Types

A reference type do not store the data itself, instead it stores a memory reference to the data.

Struct: Structs are used to define new types. They are custom data types that can group several variables of different types.

contract fooContract {
    struct fooStruct { 
        uint foo1;
        string foo2;
    }
    
    fooStruct fs;
    
    function set() public {
        fs = fooStruct(1,"tux");
    }
    
    function get() public view returns (uint) {
        return fs.foo1;
    }
}

Array: Arrays can either have fixed size or be dynamically allocated.

contract fooContract {
    uint[] fooFixArr = new uint[](2);
    uint[] fooDynlArr;
    
    function fooFunction() public {
        fooFixArr[0] = 1;
        fooFixArr[1] = 2;
         
        fooDynlArr.push(1);
        fooDynlArr.push(2);
        fooDynlArr.push(3);
    }
}

Mapping: A mapping is a dynamic key-value pair data structure similar to a hash table.

contract fooContract {
    mapping(address =&gt; uint256) public bal;

    function update(uint256 newBal) public {
        bal[msg.sender] = newBal;
    }
}




<< Prev

Next >>