Elixir 1.8.0が正規リリースされた
gumi TECH
Posted on January 16, 2019
Elixir 1.8が正規リリースされました。おもに、基盤となる部分の改善が加えられたということです。本稿は、リリースノート(英語)をもとに、つぎの4つの項目についてご説明します。
- カスタム構造検査
- タイムゾーンデータベースへの対応
- コンパイルの高速化とその他のパフォーマンス改善
- 計測・監視機能の改善と$callersの追加
カスタム構造検査
ElixirのInspect
プロトコルの実装が、データを抽出できるようになりました。データ構造を検査するときに、フィールドが簡単にフィルタリングできるのです。ユーザーのデータ構造がプライバシーに関わる情報を含んでいる場合などに使えます。たとえばつぎの構造体で、:email
や:encrypted_password
といった個人情報です。inspect/2
関数で調べると、デフォルトではすべてのフィールドが取り出されます。
defmodule User do
defstruct [:id, :name, :age, :email, :encrypted_password]
end
ログやエラーレポートなどに出力したくないデータについては、Inspect
プロトコルのカスタム実装が定められます。Elixir 1.8ではさらに、Inspect
プロトコルに@derive
を加えて、簡単にデータが抽出できるようになりました。オプション:only
でフィールドを選べば、他は表示されません。
defmodule User do
@derive {Inspect, only: [:id, :name, :age]}
defstruct [:id, :name, :age, :email, :encrypted_password]
end
inspect(%User{id: 1, name: "Homer", age: 33, address: "742 Evergreen Terrace"})
#=> #User<id: 1, name: "Homer", age: 33, ...>
オプションにはもうひとつ、表示しないフィールドを絞る:except
があります(@derive {Inspect, except: [...]}
)。
タイムゾーンデータベースへの対応
Elixir 1.3では日付と時刻を扱うために、つぎの4つのカレンダー型を備えました。
Time
Date
-
NaiveDateTime
(タイムゾーンなし) -
DateTime
(タイムゾーンあり)
その後のアップデートでカレンダー型には改善が加えられたものの、DateTime
モジュールがタイムゾーンデータベースに対応するにはいたりませんでした。
Elixir 1.8には新たにCalendar.TimeZoneDatabase
ビヘイビアが加わっています。このビヘイビアで、開発者は独自にタイムゾーンデータベースを取り込めるのです。タイムゾーンのビヘイビアに規約を明示的に定めることで、ElixirのDateTime API
が拡張できます。たとえば、DateTime
のタイムゾーンを変えるのがDateTime.shift_zone/3
関数です。Elixirはデフォルトでは、UTCのみを扱うCalendar.UTCOnlyTimeZoneDatabase
をタイムゾーンデータベースとして備えます。
そのほかカレンダーに関わる改善として、つぎの4つの関数が新しく加わりました。
コンパイルの高速化とその他のパフォーマンス改善
昨年コンパイラを改善したことにより、Elixir 1.8のコンパイルは平均5%速くなりました。さらに今回、コンパイル時間を縮め、快適な開発ができるための改善を加えています。
つぎの場合に、コンパイラはより効率的なコードを生成します。
- ガードにおける範囲確認(
x in y..z
など) - 文字リストの内挿(
'foo #{bar} baz'
など) -
Record
モジュールのレコード操作
EEx
テンプレートには共通の最適化を加え、コードは小さくなり、実行が速まりました。
計測・監視機能の改善と$callersの追加
Task
モジュールは、軽いプロセスをいくつも生成して同時に処理するためによく用いられます。そして、Elixirが新たなプロセスをつくったとき、その親を示すために付されるのが$ancestors
キーです。この情報は、計測ツールが複数のプロセス内で起こるイベントの関係を追跡するために使われます。ただ多くの場合、$ancestors
の情報だけでは足りません。
タスクはスーパーバイザーのもとで開始することが推奨されています。見通しがよくなり、ノードが落ちたときにタスクをどう終わらせるか管理できるからです。そのためには、たとえばつぎのコードのようにタスクを実行するでしょう。タスクはこのコードによりつくられます。けれどこのとき、タスクを直接生成した親はスーパーバイザーになってしまうのです。スーパーバイザーはタスクの$ancestors
リストに含まれます。けれど、コードとの関係は失われてしまうのです。
Task.Supervisor.start_child(MySupervisor, task_specification)
Elixir 1.8では、コードとタスクとの関係は、プロセスの辞書から$callers
キーで追跡できるようになりました。このキーは、$ancestors
とともに使えます。前掲のTask.Supervisor
を用いたコードでは、つぎのような関係になるでしょう。
このとき、ふたつのキー$ancestors
と$callers
に加えられるのはつぎのとおりです。
スーパーバイザーは使わず、コードから直にタスクをつくると、コードが走っているプロセスは、$ancestors
と$callers
の両方のリストに入ります。
この機能により、計測と監視のツールが、システム内で起きたイベントの追跡や関連づけをしやすくなるでしょう。さらに、Ectoサンドボックスのようなツールでも使えるのです。Ectoサンドボックスにより、データベースに対するテストは複数同時にできます。そこで用いられるトランザクションと所有メカニズムには、各プロセスが明示的に割り当てられています。$callers
がないと、データベースに問い合わせるタスクをつくっても、タスクはどこから呼び出されたのかわからず、どこに接続されているのか知ることができません。すると多くの場合、タスクに依存する機能は同時にテストできないことになります。$callers
によりこれが簡単にわかり、マシンのパワーをフルに活かしたテストが可能になるのです。
詳しい変更についてはリリースノート(英語)をご参照ください。
Posted on January 16, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.