【Pythonの方言】Googleでも使われているStarlark言語

![starlink.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/3ddd6ceb-418d-3e4b-a9d3-5480fd646473.png)
>Starlink衛星 (引用 https://satellitemap.space/)

Starlinkではなく**Starlark**です。

# Starlarkとは何か

## 概要

Starlark(旧Skylark)は、Bazelビルドシステム用に設計されたプログラミング言語ですが、他のプロジェクトにも利用可能です。

Python一方言で動的型付け・ガベージコレクション等の特徴を持ち、並列処理に適しています。

簡潔で可読性が高く、構造化データの表記や関数定義、スクリプト機能の追加などに使えます。

## 設計原則

### 決定論的評価
同じコードを二度実行すると、同じ結果が得られます。

### 閉じた実行環境
閉じた環境により、信頼できないコードや外部から持ち込まれたコードを安全に実行することができるため、セキュリティ上のリスクが低減されます。

### 並列評価
並列処理によるデータの競合や予期しない動作を防ぐことができます。
 
### シンプルさ
　シンプルなコードで、迅速にコードを読み書きしやすいです。
 
### ツールの重視
　Starlarkは人間とツールの両方によって読まれ、解析され、修正されることを認識されて設計されています。

### Pythonライク
　広く使用されているPythonに似た言語です。

## Starlarkの使い方

以下はStarlarkの構文の例です:

```python
# 数値を定義
number = 18

# 辞書を定義
people = {
    "Alice": 22,
    "Bob": 40,
    "Charlie": 55,
    "Dave": 14,
}

names = ", ".join(people.keys())  # Alice, Bob, Charlie, Dave

# 関数を定義
def greet(name):
    """挨拶を返す。"""
    return "Hello {}!".format(name)

greeting = greet(names)

above30 = [name for name, age in people.items() if age >= 30]

print("{} people are above 30.".format(len(above30)))

def fizz_buzz(n):
    """1からnまでのFizz Buzzの数字を出力。"""
    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)
```

上記のコードはPythonと非常に似ています。実際、このコードは有効なPythonコードでもあります。この短い例では、言語の大部分を示しています。Starlarkは非常に小さな言語です。

## 設計プロセス

Starlarkの設計プロセスは、以下の目標を達成することを目的としています:

- 設計提案の議論、最終状態、および進化が公開され、発見可能で、一時的でないこと
- コミュニティが変更を提案し、批評することが容易であること
- 提案のステータスと前進するために必要なものが明確であること
- 言語とAPIの意味論がより明確に指定され、再実装できること

このプロセスは、Bazelの機能の一部に焦点を当てています。あまりにも特定の、実験的な、または一時的な機能はプロセスから除外されます。目標は、ユーザーが信頼できる明確に定義され、指定されたコアを持つことです。

## Starlarkの設計

Starlarkの設計には、いくつかのPythonとの違いと簡素化があります。これにより、大規模なコードベースの保守が容易になります。

### ミュータビリティ
 データ構造（リストや辞書など）はミュータブルですが、スレッドセーフと決定論を保証するために、他のスレッドから見えるようになった時点で不変になります
```python
  a_list = [1, 2, 3]
  a_list.append(4)
  # a_listは他のスレッドから見えるようになった時点で不変になります
```
### 動的型付け
 Pythonのように、Starlarkも動的型付けを使用します。
 
### 静的な名前解決
 Starlarkは、すべてのシンボルが定義されていることを静的にチェックします
```python
def foo(): return undefined_name  # 静的エラー
```
### 例外の廃止
Starlarkには例外の概念が無く、try catchが使えません
```python
# Pythonの例
try:
    result = 1 / 0
except ZeroDivisionError:
    result = 0
```

### 無限ループの禁止
無限ループ（例: `while`）をサポートしません
### トップレベルでの単一代入
グローバル値は再代入できません
```python
magic = 17
magic = 18  # エラー: 再代入はできません
```
### トップレベルでのfor/if文の禁止
複雑なコードは関数定義の中に入れてください
### 辞書の挿入順序の決定論的な保証
多くの言語は辞書の挿入順序をランダムにしますが、Starlarkでは挿入順序が保持されます
### 繰り返し処理中の変更禁止
リストや辞書の繰り返し処理中にデータ構造が一時的に不変になります
### 単一要素のタプルには括弧が必要
1要素のタプルには括弧が必要です
```python
x = max(3, 4, 6),    # 構文エラー
x = (max(3, 4, 6),)  # 単一要素のタプル
```
### 暗黙的な文字列連結の禁止
文字列を連結するには `+` 演算子を使用する必要があります
```python
arguments = [
    "-c",
    "-O2",
    "-Wall" + "-Werror",  # `+` 演算子を使用
]
```
### ブール値は整数ではない
Pythonとは異なり、Starlarkのブール値はint型を継承しません
```python
True + True  # ランタイムエラー
True < 2     # ランタイムエラー
```
### 文字列はイテラブルではない
Starlarkの文字列はイテラブルではありません
```python
def fct(srcs):
  new_srcs = [s + ".out" for s in srcs]

fct("myfile")  # エラー: 文字列はイテラブルではありません
```
### 辞書リテラルに重複キーは許可されない
辞書リテラルに重複キーがあるとエラーになります
```python
def fct(srcs):
  new_srcs = [s + ".out" for s in srcs]

fct("myfile")  # エラー: 文字列はイテラブルではありません
```
### is演算子の廃止
is演算子はサポートされていません
### 連鎖演算子の禁止
連鎖演算子（例: `x < y > z`）はサポートされていません

## Starlarkの実装、ツール、およびユーザー

### 実装

以下の実装はまだ仕様に完全には準拠していませんが、共通のテストスイートを提供して、違いを取り除くことを目指しています。

- [Goによる実装](https://github.com/google/starlark-go/)
- [Javaによる実装](https://github.com/bazelbuild/bazel/tree/master/src/main/java/net/starlark/java)
- [Rustによる実装](https://github.com/facebookexperimental/starlark-rust)

## ツール

- [Buildifier](https://github.com/bazelbuild/buildtools): コードフォーマッタ＆リンター。未使用のロードを削除するなどの自動修正も可能
- [Stardoc](https://skydoc.bazel.build/): ドキュメントジェネレータ
- [Starlark Playground](https://github.com/qri-io/starpg): WebベースのStarlarkエディタ。golang実装のStarlarkを使用し、Python構文に設定されたmonacoエディタを提供
- [Moonlark](https://github.com/obazl/moonlark): Luaバインディングを持つCによるStarlarkパーサー

## ライブラリと拡張

- [Skycfg](https://github.com/stripe/skycfg): プロトコルバッファメッセージを生成するためのStarlarkライブラリ
- [starlark-go-nethttp](https://github.com/pcj/starlark-go-nethttp): starlark-go内で使用するための`net/httpパッケージ`の最小サブセットをラップするライブラリ
- [Starlet](https://github.com/1set/starlet): GoのStarlarkラッパーで、スクリプト実行を簡素化し、データ変換を提供し、便利なStarlarkライブラリと拡張機能を提供
- [Starlight](https://github.com/starlight-go/starlight): GoのStarlarkインタプリタをラップするライブラリ

### IDE

いくつかのIDEには[Bazel用のプラグイン](https://bazel.build/install/ide)があります。それ以外の場合は、Pythonモードを使用することを検討してください。

## ユーザー

- [Bazel](https://github.com/bazelbuild/bazel): 高速でスケーラブルなマルチ言語ビルドシステム。StarlarkはBazelのために設計されました
- [Buck2](https://buck2.build/): Metaからのビルドシステムで、Bazelと同様にStarlarkを使用します
- [Caddy](https://caddyserver.com/): 高速なクロスプラットフォームHTTP/2ウェブサーバーで、自動HTTPSを提供。[Starlarkを使用](https://github.com/caddyserver/caddy/tree/v2#json-is-declarative-what-if-i-need-more-programmability-ie-imperative-syntax)してJSON構成を拡張し、ロジックを追加します
- [Copybara](https://github.com/google/copybara): リポジトリ間でコードを変換および移動するツール。ワークフローを構成するためにStarlarkを埋め込みます。
- [Delve](https://github.com/go-delve/delve): Go言語のデバッガで、完全な機能を備えたデバッグツールを提供することを目指しています。[DelveはStarlarkを使用](https://github.com/go-delve/delve/blob/master/Documentation/cli/starlark.md)してスクリプト言語として使用します
- [Drone](https://drone.io): セルフサービスの継続的デリバリープラットフォーム。yaml構成の代替として[Starlarkスクリプト](https://docs.drone.io/starlark/overview/)をサポートしています
- [Isopod](https://github.com/cruise-automation/isopod): Kubernetes構成のためのDSLフレームワーク。Kubernetesオブジェクトをプロトコルバッファとしてレンダリングします
- [lucicfg](https://chromium.googlesource.com/infra/luci/luci-go/+/refs/heads/master/lucicfg/doc/README.md): Chromium CIからのツールで、Starlarkから低レベルの構成ファイルを生成します
- [Pixlet](https://github.com/tidbyt/pixlet): 小型LEDディスプレイ（例: [Tidbyt](https://tidbyt.com/)）向けにアニメーションを生成するランタイムおよびUXツールキット。Starlarkを使用してWebPアニメーションを生成するアプレットを記述します
- [qri](http://qri.io/): バージョン管理、スクリプト化、エクスポート可能、コラボレーティブなデータセット。Starlarkを使用して[変換を記述](https://qri.io/docs/reference/starlark_syntax/)します
- [Tilt](https://tilt.dev/): Kubernetesにデプロイするチームのローカル開発インスタンスを管理します。[Tiltファイル](https://docs.tilt.dev/tiltfile_concepts.html)はStarlarkで記述されます
- [Vela](https://go-vela.github.io/docs/): 継続的インテグレーションおよびデリバリープラットフォーム。[Starlarkスクリプト](https://go-vela.github.io/docs/templates/tutorials/starlark/)をYAMLの代替としてサポートしています
- [ytt](https://get-ytt.io/): YAML構造を理解し、データに焦点を当てることを可能にするテンプレートツール。IBMの[ブログ記事](https://developer.ibm.com/blogs/yaml-templating-tool-to-simplify-complex-configuration-management/)も参照してください

## おわりに

Starlarkは、シンプルでPythonに似た構文を持つ構成言語として設計されています。その決定論的評価、閉じた実行環境、並列評価の特徴により、信頼性と安全性を兼ね備えています。Bazelビルドシステムをはじめとするさまざまなプロジェクトでの使用が期待されています。Starlarkの詳細については、公式リポジトリや仕様書を参照してください。

[Starlark(GitHub)](https://github.com/bazelbuild/starlark)

今後もStarlarkを用いた開発が進むことで、より効率的で安全なプロジェクト運用が実現されることを期待しています。興味を持たれた方は、ぜひ一度試してみてください。

もしこの記事が役に立ったと感じたら、いいねやストックをお願いします！