diff options
author | Laurent Le Brun <laurentlb@google.com> | 2016-06-20 14:57:13 +0000 |
---|---|---|
committer | Philipp Wollermann <philwo@google.com> | 2016-06-21 09:57:55 +0000 |
commit | 20c0bb24ff9ed59ee89c6696c3706412e8a87022 (patch) | |
tree | 1012091e6700367c02504bc5702c5f0398b405a2 /site | |
parent | a469e8f340aa211a2adcee666d61ca32e52ddbea (diff) |
Improve Skylark mutability documentation.
--
MOS_MIGRATED_REVID=125336857
Diffstat (limited to 'site')
-rw-r--r-- | site/docs/skylark/concepts.md | 83 |
1 files changed, 53 insertions, 30 deletions
diff --git a/site/docs/skylark/concepts.md b/site/docs/skylark/concepts.md index cb40991a2d..48ee7d0b02 100644 --- a/site/docs/skylark/concepts.md +++ b/site/docs/skylark/concepts.md @@ -72,6 +72,12 @@ A build consists of three phases. required. If a file is missing or if a command fails to generate one output, the build fails. Tests are run during this phase, as they are actions. +Bazel uses parallelism to read, parse and evaluate the `.bzl` files and `BUILD` +files. A file is read at most once per build and the result of the evaluation is +cached and reused. A file is evaluated only once all its dependencies (`load()` +statements) have been resolved. By design, loading a `.bzl` file has no visible +side-effect, it only defines values and functions. + ## Language Skylark is a superset of the core build language and its syntax is a subset of @@ -81,31 +87,53 @@ It is designed to be simple, thread-safe and integrated with the BUILD language. It is not a general-purpose language and most Python features are not included. +## Mutability + +Because evaluation of BUILD and .bzl files is performed in parallel, there are +some restrictions in order to guarantee thread-safety and determinism. Two +mutable data structures are available: [lists](lib/list.html) and +[dicts](lib/dict.html). Unlike in Python, [sets](lib/set.html) are not mutable. + +In a build, there are many "evaluation contexts": each `.bzl` file and each +`BUILD` file is loaded in a different context. Each rule is also analyzed in a +separate context. We allow side-effects (e.g. appending a value to a list or +deleting an entry in a dictionary) only on objects created during the current +evaluation context. + +For example, here is the content of the file `foo.bzl`: + +```python +var = [] + +def fct(): + var.append(5) -Some differences with Python should be noted: - -* Although some data structures are mutable, all objects are recursively frozen - and become recursively immutable before Bazel invokes Skylark - and after it is done with such evaluation, - i.e. when a .bzl file is loaded, when a BUILD file is processed, - when a Skylark-defined rule is evaluated to create a configured target, or - when a callback function is called to compute a configured target attribute. - These objects that are frozen notably include the recursive contents of any - global variable exported by a .bzl file or imported by a `load()` statement, - and any parameter passed to a callback function or result returned by it. - From the point of view of the Skylark code - in given a Bazel-initiated evaluation, - objects passed as input or present in the evaluation's initial environment - are immutable, whereas objects created during the evaluation are mutable. - From the point of view of the Bazel code that evaluates said Skylark code, - all inputs and outputs of the evaluation are recursively immutable - and all evaluations are deterministic, - which guarantees the hermeticity of the build, - and allows sharing of evaluations without any fear of side-effects. - -* Lists are mutable, but dicts and sets are immutable. - This is temporary: dicts will be made mutable in the near future; - however there are no plans to make sets mutable at this time. +fct() +``` + +The variable `var` is created when `foo.bzl` is loaded. `fct()` is called during +the same context, so it is safe. At the end of the evaluation, the definition +`var = [5]` is exported. Any other file can load it, and it is possible that +multiple files will load it at the same time. For this reason, the following +code is not legal: + +```python +load(":foo.bzl", "var", "fct") + +var.append(6) # not allowed + +fct() # not allowed +``` + +Since the call to `fct()` attempts to mutate the shared variable `var`, it will +fail. `fct()` can only be called during the evaluation of `foo.bzl`. It cannot +be called from another file. It is also forbidden to call it during the analysis +phase (i.e. when a custom rule is analyzed). + +## Differences with Python + +In addition to the mutability restrictions, there are also differences with +Python: * All global values are constant (they cannot be reassigned). @@ -120,14 +148,9 @@ Some differences with Python should be noted: operand. If you need compatibility with Python, we suggest this syntax: `dict(a.items() + b.items())`. -* Dictionary assignment has slightly different semantics: `d["x"] = y` is - syntactic sugar for `d = d + {"x": y}` or `d += {"x": y}`. This behavior - is temporary, and will follow Python semantics in the future. - * Dictionaries have deterministic order when iterating (sorted by key). -* Sets use a custom order when iterating (see - [documentation](lib/globals.html#set)). +* Sets use a custom order when iterating (see [documentation](lib/globals.html#set)). * Recursion is not allowed. |