aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/contracts.rst33
-rw-r--r--docs/control-structures.rst27
-rw-r--r--docs/frequently-asked-questions.rst25
-rw-r--r--docs/miscellaneous.rst23
4 files changed, 55 insertions, 53 deletions
diff --git a/docs/contracts.rst b/docs/contracts.rst
index d4160eac..4d439b26 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -50,7 +50,7 @@ This means that cyclic creation dependencies are impossible.
pragma solidity >=0.4.22 <0.6.0;
contract OwnedToken {
- // TokenCreator is a contract type that is defined below.
+ // `TokenCreator` is a contract type that is defined below.
// It is fine to reference it as long as it is not used
// to create a new contract.
TokenCreator creator;
@@ -61,14 +61,18 @@ This means that cyclic creation dependencies are impossible.
// creator and the assigned name.
constructor(bytes32 _name) public {
// State variables are accessed via their name
- // and not via e.g. this.owner. This also applies
- // to functions and especially in the constructors,
- // you can only call them like that ("internally"),
- // because the contract itself does not exist yet.
+ // and not via e.g. `this.owner`. Functions can
+ // be accessed directly or through `this.f`,
+ // but the latter provides an external view
+ // to the function. Especially in the constructor,
+ // you should not access functions externally,
+ // because the function does not exist yet.
+ // See the next section for details.
owner = msg.sender;
+
// We do an explicit type conversion from `address`
// to `TokenCreator` and assume that the type of
- // the calling contract is TokenCreator, there is
+ // the calling contract is `TokenCreator`, there is
// no real way to check that.
creator = TokenCreator(msg.sender);
name = _name;
@@ -86,10 +90,11 @@ This means that cyclic creation dependencies are impossible.
// Only the current owner can transfer the token.
if (msg.sender != owner) return;
- // We also want to ask the creator if the transfer
- // is fine. Note that this calls a function of the
- // contract defined below. If the call fails (e.g.
- // due to out-of-gas), the execution also fails here.
+ // We ask the creator contract if the transfer
+ // should proceed by using a function of the
+ // `TokenCreator` contract defined below. If
+ // the call fails (e.g. due to out-of-gas),
+ // the execution also fails here.
if (creator.isTokenTransferOK(owner, newOwner))
owner = newOwner;
}
@@ -100,8 +105,8 @@ This means that cyclic creation dependencies are impossible.
public
returns (OwnedToken tokenAddress)
{
- // Create a new Token contract and return its address.
- // From the JavaScript side, the return type is simply
+ // Create a new `Token` contract and return its address.
+ // From the JavaScript side, the return type is
// `address`, as this is the closest type available in
// the ABI.
return new OwnedToken(name);
@@ -113,12 +118,14 @@ This means that cyclic creation dependencies are impossible.
tokenAddress.changeName(name);
}
+ // Perform checks to determine if transferring a token to the
+ // `OwnedToken` contract should proceed
function isTokenTransferOK(address currentOwner, address newOwner)
public
pure
returns (bool ok)
{
- // Check some arbitrary condition.
+ // Check an arbitrary condition to see if transfer should proceed
return keccak256(abi.encodePacked(currentOwner, newOwner))[0] == 0x7f;
}
}
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 9da29d14..5e3b722b 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -2,7 +2,7 @@
Expressions and Control Structures
##################################
-.. index:: ! parameter, parameter;input, parameter;output
+.. index:: ! parameter, parameter;input, parameter;output, parameter;multiple
Input Parameters and Output Parameters
======================================
@@ -32,6 +32,8 @@ something like::
Input parameters can be used just as any other local variable
can be used, they can also be assigned to.
+.. index:: return array, return string, array, string, array of strings, dynamic array, variably sized array, return struct, struct
+
Output Parameters
-----------------
@@ -54,12 +56,21 @@ write::
}
The names of output parameters can be omitted.
-The output values can also be specified using ``return`` statements,
+The return values can be specified using ``return`` statements,
which are also capable of :ref:`returning multiple values<multi-return>`.
Return parameters can be used as any other local variable and they
are zero-initialized; if they are not explicitly
set, they stay zero.
+
+.. note::
+ You cannot return some types from non-internal functions, notably
+ multi-dimensional dynamic arrays and structs. If you enable the
+ new experimental ``ABIEncoderV2`` feature by adding ``pragma experimental
+ ABIEncoderV2;`` to your source file then more types are available, but
+ ``mapping`` types are still limited to inside a single contract and you
+ cannot transfer them.
+
.. index:: if, else, while, do/while, for, break, continue, return, switch, goto
Control Structures
@@ -120,8 +131,8 @@ External Function Calls
The expressions ``this.g(8);`` and ``c.g(2);`` (where ``c`` is a contract
instance) are also valid function calls, but this time, the function
will be called "externally", via 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.
+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.
@@ -130,8 +141,10 @@ all function arguments have to be copied to memory.
A function call from one contract to another does not create its own transaction,
it is a message call as part of the overall transaction.
-When calling functions of other contracts, the amount of Wei sent with the call and
-the gas can be specified with special options ``.value()`` and ``.gas()``, respectively::
+When calling functions of other contracts, you can specify the amount of Wei or gas sent with the call with the special options ``.value()`` and ``.gas()``, respectively. Any Wei you send to the contract is added to the total balance of the contract:
+
+
+::
pragma solidity >=0.4.0 <0.6.0;
@@ -400,7 +413,7 @@ In any case, you will get a warning about the outer variable being shadowed.
}
}
-.. index:: ! exception, ! throw, ! assert, ! require, ! revert
+.. index:: ! exception, ! throw, ! assert, ! require, ! revert, ! errors
.. _assert-and-require:
diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst
index 3e9a6aca..8b655b0d 100644
--- a/docs/frequently-asked-questions.rst
+++ b/docs/frequently-asked-questions.rst
@@ -38,11 +38,6 @@ has it (which includes `Remix <https://remix.ethereum.org/>`_), then
``contractname.kill.sendTransaction({from:eth.coinbase})``, just the same as my
examples.
-Can you return an array or a ``string`` from a solidity function call?
-======================================================================
-
-Yes. See `array_receiver_and_returner.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/60_array_receiver_and_returner.sol>`_.
-
Is it possible to in-line initialize an array like so: ``string[] myarray = ["a", "b"];``
=========================================================================================
@@ -61,11 +56,6 @@ Example::
}
}
-Can a contract function return a ``struct``?
-============================================
-
-Yes, but only in ``internal`` function calls or if ``pragma experimental "ABIEncoderV2";`` is used.
-
If I return an ``enum``, I only get integer values in web3.js. How to get the named values?
===========================================================================================
@@ -103,15 +93,6 @@ How do structs work?
See `struct_and_for_loop_tester.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/65_struct_and_for_loop_tester.sol>`_.
-How do for loops work?
-======================
-
-Very similar to JavaScript. Such as the following example:
-
-``for (uint i = 0; i < a.length; i ++) { a[i] = i; }``
-
-See `struct_and_for_loop_tester.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/65_struct_and_for_loop_tester.sol>`_.
-
What are some examples of basic string manipulation (``substring``, ``indexOf``, ``charAt``, etc)?
==================================================================================================
@@ -292,12 +273,6 @@ In this example::
}
}
-Can a contract function accept a two-dimensional array?
-=======================================================
-
-If you want to pass two-dimensional arrays across non-internal functions,
-you most likely need to use ``pragma experimental "ABIEncoderV2";``.
-
What is the relationship between ``bytes32`` and ``string``? Why is it that ``bytes32 somevar = "stringliteral";`` works and what does the saved 32-byte hex value mean?
========================================================================================================================================================================
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index 8cc52c8f..8e4e8b99 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -31,6 +31,14 @@ Statically-sized variables (everything except mapping and dynamically-sized arra
declaring your storage variables in the order of ``uint128, uint128, uint256`` instead of
``uint128, uint256, uint128``, as the former will only take up two slots of storage whereas the
latter will take up three.
+
+ .. note::
+ The layout of state variables in storage is considered to be part of the external interface
+ of Solidity due to the fact that storage pointers can be passed to libraries. This means that
+ any change to the rules outlined in this section is considered a breaking change
+ of the language and due to its critical nature should be considered very carefully before
+ being executed.
+
The elements of structs and arrays are stored after each other, just as if they were given explicitly.
@@ -165,16 +173,16 @@ Different types have different rules for cleaning up invalid values:
.. index:: optimizer, common subexpression elimination, constant propagation
*************************
-Internals - The Optimizer
+Internals - The Optimiser
*************************
-The Solidity optimizer operates on assembly, so it can be and also is used by other languages. It splits the sequence of instructions into basic blocks at ``JUMPs`` and ``JUMPDESTs``. Inside these blocks, the instructions are analysed and every modification to the stack, to memory or storage is recorded as an expression which consists of an instruction and a list of arguments which are essentially pointers to other expressions. The main idea is now to find expressions that are always equal (on every input) and combine them into an expression class. The optimizer first tries to find each new expression in a list of already known expressions. If this does not work, the expression is simplified according to rules like ``constant + constant = sum_of_constants`` or ``X * 1 = X``. Since this is done recursively, we can also apply the latter rule if the second factor is a more complex expression where we know that it will always evaluate to one. Modifications to storage and memory locations have to erase knowledge about storage and memory locations which are not known to be different: If we first write to location x and then to location y and both are input variables, the second could overwrite the first, so we actually do not know what is stored at x after we wrote to y. On the other hand, if a simplification of the expression x - y evaluates to a non-zero constant, we know that we can keep our knowledge about what is stored at x.
+The Solidity optimiser operates on assembly so that other languages can use it. It splits the sequence of instructions into basic blocks at ``JUMPs`` and ``JUMPDESTs``. Inside these blocks, the optimiser analyses the instructions and records every modification to the stack, memory, or storage as an expression which consists of an instruction and a list of arguments which are pointers to other expressions. The optimiser uses a component called "CommonSubexpressionEliminator" that amongst other tasks, finds expressions that are always equal (on every input) and combines them into an expression class. The optimiser first tries to find each new expression in a list of already known expressions. If this does not work, it simplifies the expression according to rules like ``constant + constant = sum_of_constants`` or ``X * 1 = X``. Since this is a recursive process, we can also apply the latter rule if the second factor is a more complex expression where we know that it always evaluates to one. Modifications to storage and memory locations have to erase knowledge about storage and memory locations which are not known to be different. If we first write to location x and then to location y and both are input variables, the second could overwrite the first, so we do not know what is stored at x after we wrote to y. If simplification of the expression x - y evaluates to a non-zero constant, we know that we can keep our knowledge about what is stored at x.
-At the end of this process, we know which expressions have to be on the stack in the end and have a list of modifications to memory and storage. This information is stored together with the basic blocks and is used to link them. Furthermore, knowledge about the stack, storage and memory configuration is forwarded to the next block(s). If we know the targets of all ``JUMP`` and ``JUMPI`` instructions, we can build a complete control flow graph of the program. If there is only one target we do not know (this can happen as in principle, jump targets can be computed from inputs), we have to erase all knowledge about the input state of a block as it can be the target of the unknown ``JUMP``. If a ``JUMPI`` is found whose condition evaluates to a constant, it is transformed to an unconditional jump.
+After this process, we know which expressions have to be on the stack at the end, and have a list of modifications to memory and storage. This information is stored together with the basic blocks and is used to link them. Furthermore, knowledge about the stack, storage and memory configuration is forwarded to the next block(s). If we know the targets of all ``JUMP`` and ``JUMPI`` instructions, we can build a complete control flow graph of the program. If there is only one target we do not know (this can happen as in principle, jump targets can be computed from inputs), we have to erase all knowledge about the input state of a block as it can be the target of the unknown ``JUMP``. If the optimiser finds a ``JUMPI`` whose condition evaluates to a constant, it transforms it to an unconditional jump.
-As the last step, the code in each block is completely re-generated. A dependency graph is created from the expressions on the stack at the end of the block and every operation that is not part of this graph is essentially dropped. Now code is generated that applies the modifications to memory and storage in the order they were made in the original code (dropping modifications which were found not to be needed) and finally, generates all values that are required to be on the stack in the correct place.
+As the last step, the code in each block is re-generated. The optimiser creates a dependency graph from the expressions on the stack at the end of the block, and it drops every operation that is not part of this graph. It generates code that applies the modifications to memory and storage in the order they were made in the original code (dropping modifications which were found not to be needed). Finally, it generates all values that are required to be on the stack in the correct place.
-These steps are applied to each basic block and the newly generated code is used as replacement if it is smaller. If a basic block is split at a ``JUMPI`` and during the analysis, the condition evaluates to a constant, the ``JUMPI`` is replaced depending on the value of the constant, and thus code like
+These steps are applied to each basic block and the newly generated code is used as replacement if it is smaller. If a basic block is split at a ``JUMPI`` and during the analysis, the condition evaluates to a constant, the ``JUMPI`` is replaced depending on the value of the constant. Thus code like
::
@@ -185,15 +193,14 @@ These steps are applied to each basic block and the newly generated code is used
else
return 1;
-is simplified to code which can also be compiled from
+still simplifies to code which you can compile even though the instructions contained
+a jump in the beginning of the process:
::
data[7] = 9;
return 1;
-even though the instructions contained a jump in the beginning.
-
.. index:: source mappings
***************