blob: 4e8a3a5a6ad9329ce4232eed3146d2c45dd2fa27 [file] [log] [blame] [view]
---
layout: documentation
title: Starlark language
category: extending
---
# Starlark Language
<!-- [TOC] -->
This page is an overview of [Starlark](https://github.com/bazelbuild/starlark),
formerly known as Skylark, the language used in Bazel. For a complete list of
functions and types, check [Starlark's API reference](lib/skylark-overview.html).
For more information about the language, see [Starlark's GitHub repo](https://github.com/bazelbuild/starlark/).
## Syntax
Starlark's syntax is inspired by Python3. This is valid syntax in Starlark:
```python
def fizz_buzz(n):
"""Print Fizz Buzz numbers from 1 to n."""
for i in range(1, n + 1):
s = ""
if i % 3 == 0:
s += "Fizz"
if i % 5 == 0:
s += "Buzz"
print(s if s else i)
fizz_buzz(20)
```
Starlark's semantics can differ from Python, but behavioral differences are
rare, except for cases where Starlark raises an error. The following Python
types are supported:
* [None](lib/globals.html#None)
* [bool](lib/bool.html)
* [dict](lib/dict.html)
* function
* [int](lib/int.html)
* [list](lib/list.html)
* [string](lib/string.html)
## Mutability
Starlark favors immutability. Two mutable data structures are available:
[lists](lib/list.html) and [dicts](lib/dict.html). Changes to mutable
data-structures, such as appending a value to a list or deleting an entry in a
dictionary are valid only for objects created in the current context. After a
context finishes, its values become immutable.
This is because Bazel builds use parallel execution. During a build, each `.bzl`
file and each `BUILD` file get their own execution context. Each rule is also
analyzed in its own context.
Let's go through an example with the file `foo.bzl`:
```python
# `foo.bzl`
var = [] # declare a list
def fct(): # declare a function
var.append(5) # append a value to the list
fct() # execute the fct function
```
Bazel creates `var` when `foo.bzl` loads. `var` is thus part of `foo.bzl`'s
context. When `fct()` runs, it does so within the context of `foo.bzl`. After
evaluation for `foo.bzl` completes, the environment contains an immutable entry,
`var`, with the value `[5]`.
When another `bar.bzl` loads symbols from `foo.bzl`, loaded values remain
immutable. For this reason, the following code in `bar.bzl` is illegal:
```python
# `bar.bzl`
load(":foo.bzl", "var", "fct") # loads `var`, and `fct` from `./foo.bzl`
var.append(6) # runtime error, the list stored in var is frozen
fct() # runtime error, fct() attempts to modify a frozen list
```
Global variables defined in `bzl` files cannot be changed outside of the
`bzl` file that defined them. Just like the above example using `bzl` files,
values returned by rules are immutable.
## Differences between BUILD and .bzl files
`BUILD` files register targets via making calls to rules. `.bzl` files provide
definitions for constants, rules, macros, and functions.
[Native functions](../be/functions.html) and [native rules](
../be/overview.html#language-specific-native-rules) are global symbols in
`BUILD` files. `bzl` files need to load them using the [`native` module](
https://docs.bazel.build/versions/master/skylark/lib/native.html).
There are two syntactic restrictions in `BUILD` files: 1) declaring functions is
illegal, and 2) `*args` and `**kwargs` arguments are not allowed.
## Differences with Python
* Global variables are immutable.
* `for` statements are not allowed at the top-level. Use them within functions
instead. In `BUILD` files, you may use list comprehensions.
* `if` statements are not allowed at the top-level. However, `if` expressions
can be used: `first = data[0] if len(data) > 0 else None`.
* Deterministic order for iterating through Dictionaries.
* Recursion is not allowed.
* Int type is limited to 32-bit signed integers. Overflows will throw an error.
* Modifying a collection during iteration is an error.
* Except for equality tests, comparison operators `<`, `<=`, `>=`, `>`, etc. are
not defined across value types. In short: `5 < 'foo'` will throw an error and
`5 == "5"` will return false.
* In tuples, a trailing comma is valid only when the tuple is between
parentheses, e.g. write `(1,)` instead of `1,`.
* Dictionary literals cannot have duplicated keys. For example, this is an
error: `{"a": 4, "b": 7, "a": 1}`.
* Strings are represented with double-quotes (e.g. when you call
[repr](lib/globals.html#repr)).
* Strings aren't iterable.
The following Python features are not supported:
* implicit string concatenation (use explicit `+` operator).
* Chained comparisons (e.g. `1 < x < 5`).
* `class` (see [`struct`](lib/struct.html#struct) function).
* `import` (see [`load`](concepts.md#loading-an-extension) statement).
* `while`, `yield`.
* float and set types.
* generators and generator expressions.
* `lambda` and nested functions.
* `is` (use `==` instead).
* `try`, `raise`, `except`, `finally` (see [`fail`](lib/globals.html#fail) for fatal errors).
* `global`, `nonlocal`.
* most builtin functions, most methods.