Language Description
bin@57blocks.com
Layout of a Solidity Source File
Source files can contain an arbitrary number of SPDX License Identifier, pragmas, imports and comments.
Structure of a Contract
Contracts in Solidity are similar to classes in object-oriented languages. Each contract can contain declarations of State Variables, Functions, Function Modifiers, Events, Errors, Struct Types and Enum Types. Furthermore, contracts can inherit from other contracts.
Types
Solidity is a statically typed language, which means that the type of each variable (state and local) needs to be specified. Solidity provides several elementary types which can be combined to form complex types.
1. Value Types
The following are called value types because their variables will always be passed by value, i.e. they are always copied when they are used as function arguments or in assignments.
Booleans, Integers, Fixed Point Numbers, Address, Contract Types, Enums, Literals(Address Literals, Rational and Integer Literals, Hexadecimal Literals, String Literals and Types, Unicode Literals)
Bold types are unique in Solidity.
2. Reference Types
Values of reference type can be modified through multiple different names. Contrast this with value types where you get an independent copy whenever a variable of value type is used. Because of that, reference types have to be handled more carefully than value types. Currently, reference types comprise structs, arrays and mappings.
a. Data location
Every reference type has an additional annotation, the “data location”, about where it is stored. There are three data locations: memory, storage and calldata. 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).
This part is very important and needs to be read and understood carefully.
b. Arrays
Arrays can have a compile-time fixed size, or they can have a dynamic size.
The type of an array of fixed size k and element type T is written as T[k], and an array of dynamic size as T[].
c. Structs
Solidity provides a way to define new types in the form of structs.
d. Mapping Types
Mapping types use the syntax mapping(KeyType KeyName? => ValueType ValueName?) and variables of mapping type are declared using the syntax mapping(KeyType KeyName? => ValueType ValueName?) VariableName. The KeyType can be any built-in value type, bytes, string, or any contract or enum type. Other user-defined or complex types, such as mappings, structs or array types are not allowed. ValueType can be any type, including mappings, arrays and structs. KeyName and ValueName are optional (so mapping(KeyType => ValueType) works as well) and can be any valid identifier that is not a type.
Control Structures
Most of the control structures known from curly-braces languages are available in Solidity:
There is: if, else, while, do, for, break, continue, return
, with the usual semantics known from C or JavaScript.
Solidity also supports exception handling in the form of try/catch
-statements, but only for external function calls and contract creation calls. Errors can be created using the revert statement.
1. Function Calls
a. Internal Function Calls
Functions of the current contract can be called directly (“internally”), also recursively. These function calls are translated into simple jumps inside the EVM. This has the effect that the current memory is not cleared, i.e. passing memory references to internally-called functions is very efficient. Only functions of the same contract instance can be called internally.
b. External Function Calls
Functions can also be called using the this.g(8)
; and c.g(2)
; notation, where c
is a contract instance and g
is a function belonging to c
. Calling the function g
via either way results in it being called “externally”, using a message call and not directly via jumps. Please note that function calls on this
cannot be used in the constructor, as the actual contract has not been created yet.
Functions of other contracts have to be called externally. For an external call, all function arguments have to be copied to memory.
Contracts
Contracts in Solidity are similar to classes in object-oriented languages. They contain persistent data in state variables, and functions that can modify these variables. Calling a function on a different contract (instance) will perform an EVM function call and thus switch the context such that state variables in the calling contract are inaccessible. A contract and its functions need to be called for anything to happen. There is no “cron” concept in Ethereum to call a function at a particular event automatically.
This part is very important and needs to be read and understood carefully.
1. State Variable Visibility - public, internal, private
Function Visibility - external, public, internal, private
2. Getter Functions
The compiler automatically creates getter functions for all public state variables.
3. Function Modifiers
Modifiers can be used to change the behaviour of functions in a declarative way. For example, you can use a modifier to automatically check a condition prior to executing the function.
4. Constant and Immutable State Variables
State variables can be declared as constant or immutable. In both cases, the variables cannot be modified after the contract has been constructed. For constant variables, the value has to be fixed at compile-time, while for immutable, it can still be assigned at construction time.
5. Functions
Functions can be defined inside and outside of contracts.
6. Events
Solidity events give an abstraction on top of the EVM’s logging functionality. Applications can subscribe and listen to these events through the RPC interface of an Ethereum client.
7. Errors and the Revert Statement
Errors in Solidity provide a convenient and gas-efficient way to explain to the user why an operation failed. They can be defined inside and outside of contracts (including interfaces and libraries).
8. Inheritance
Solidity supports multiple inheritance including polymorphism.
9. Abstract Contracts
Contracts must be marked as abstract when at least one of their functions is not implemented or when they do not provide arguments for all of their base contract constructors. Even if this is not the case, a contract may still be marked abstract, such as when you do not intend for the contract to be created directly.
10. Interfaces
Interfaces are similar to abstract contracts, but they cannot have any functions implemented.
11. Libraries
Libraries are similar to contracts, but their purpose is that they are deployed only once at a specific address and their code is reused using the DELEGATECALL (CALLCODE until Homestead) feature of the EVM.
12. Using For
The directive using A for B can be used to attach functions (A) as operators to user-defined value types or as member functions to any type (B). The member functions receive the object they are called on as their first parameter (like the self variable in Python). The operator functions receive operands as parameters.