authors/bcardiff.jpg authors/makenowjust.jpg Brian J. Cardiff TSUYUSATO Kitsune (翻訳) 3 weeks and 6 days ago

Crystal 0.35.0がリリースされました!

Crystal 0.35.0 がリリースされました。

今回のリリースはみなさんの待ち望んでいた、1.0直前の標準ライブラリに磨きをかけるものです。この中には最近のいくつかの追加やより洗練された実装の繰り返しといった、多くの活動があります。他には、デバッグの改善や Windows のサポート、その他のプラットフォームでのランタイムの安定化などを含みます。

このリリースが最後のバージョン 0.x のリリースになるでしょう。1.0.0-preX のリリースに向けて準備をしていてください。

38人のコントリビューターによって0.34.0から242のコミットがありました。

それでは今回のリリースのハイライトを紹介していきます。たくさんの紹介するものがあります。ですが、リリースのチェンジログにもたくさんの価値ある情報があることを忘れないでください。

言語の変更

網羅性チェック (テイク2)

前回のリリースで、コンパイラは case 文の条件節の網羅性チェックをするようになりました。ですが、フィーバックを受けて、次のことを決定しました。

  1. case ... when を前のように戻す。暗黙の else nil があって、条件節は網羅的でなくてもよい。
  2. case ... in 文を実験的に導入する。こちらは暗黙の else を持たず、条件の網羅性が確認できなければコンパイルが通らない。実験的というのはフォードバックを元に変更される可能性がある、ということです。たとえマイナーリリースの間でも、その変更は行なわれる可能性があります。

この決定によって case ... when の意味は身近なままとなり、既存のコードに影響することなく網羅性チェックをする case 文を洗練させていくことが可能になります。より詳細な議論は#9258#9045を参照してください。

# Compiles! Totally fine
case 1 || "a"
when Int32
end

# Error: missing case String
case 1 || "a"
in Int32
end

この変更によって in が正式なキーワードとなりました。これは破壊的な変更ですが、in はこれまでもマクロ中ではキーワードとして扱われていました。

コンパイラ

コンパイラに破壊的な変更があり、コンパイラの CLI がシバン #! によるスクリプトをより安心して動作させられるようになりました。これからは、コマンドの代わりにファイルを引数にしてコンパイラを実行すると (crystal path/to/file.cr arg1 arg2 のように)、ファイルがコンパイルされて、そしてそれを実行する、という動作をします。このとき、引数はプログラムにだけ影響して、コンパイラに影響しない、ということです。

コンパイラフラグを使いたい場合や引数と共にプログラムを実行したい場合は、次のように run コマンドが使えます。crystal run path/to/file.cr -Dcompiler_flag --release -- arg1 arg2-- はコンパイラのオプションとプログラムのオプションを切り分けます。詳細は#9171を確認してください。

他の破壊的な変更としては、crystal env がシェル向けにクオートをするようになりました。つまり、eval "$(crystal env)" が安全にできるようになったということです。また、crystal env VARIABLE はこれまでの通りです。詳細は#9428を確認してください。

パーサーはたくさんの愛を受けました。エッジケースの修正や、そこそこのリファクタリングが#9208でされています。

言語のいくつかの機能はより良い動作のために反芻が必要でした。このリリースではオートキャストが多重ディスパッチやユニオンのデフォルト値に対して動作するようになりました。詳細は#9004#9366を確認してください。これはいくつかの場合の予期しない残念な挙動を解決するでしょう。

既存の機能の改善の背景には、Crystal のデバッグ機能の改善を待ち望まれていたことがあります。この改善はまだ完了してはいませんが、#8538で大きな一歩を踏み出すことができました。この VSCode で Crystal のプログラムをどうやってデバッグするかを説明した記事で、どう設定すれば良いかや、スクリーンショットを確認できます。

@[Link] アノテーションは少しだけ再デザインされました。pkg-config とより統合されて、static: オプションのサポートが無くなりました。これによって将来、デフォルト値をいい感じに提供しつつ、リンクを詳細に設定できるようにすることを見据えています。詳細は#8972を確認してください。

Crystal パッケージのメンテナにとって、コンパイラをビルドする際にCRYSTAL_CONFIG_PATH が標準ライブラリのパスのみを必要とするようになったという知らせは価値があるでしょう。lib ディレクトリはコンパイラによって常に含まれるようになりました。将来的には shaeds のインストールパスを細かく設定できるようにしたいと考えています。詳細は#9315を確認してください。

その他の変更として、SOURCE_DATE_EPOCH という環境変数を使うことでコンパイラをビルドする際にソースコードの時刻を伝えることができるようになりました。詳細は#9088を確認してください。

Shards

Shards v0.11.1 が今回のリリースではバンドルされます。

今回の把握すべき主要な変更は crystal: プロパティが効果的に機能するようになった点です。このプロパティは、有効な shard のバージョンを Crystal 環境に基いて決定するのに使われます。詳細は動作は shards/SPEC.md を確認してください。

後方互換性のために crystal: プロパティが shard.yml に無かった場合、< 1.0.0として解釈されます。よって、Crystal 1.0.0 まではそのままでも動作し続けるでしょう。また、この挙動が不便な場合は、--ignore-crystal-version を渡すことでこのチェックを無視できます。

利用者の期待を高めるには、依存するバージョンを明示する必要があると考えられます。そして、標準ライブラリや言語のバージョンもまた依存関係なのです。

crystal: プロパティの動作は依存関係のバージョン指定とほとんど同じように動作します。違いは、利便性のため crystal: x.y.z~> x.y, >= x.y.z のように (つまり、 >= x.y.z, < (x+1).0.0) 解釈されることです。この結果、任意のメジャーリリースで何らかの対応が必要になります。

shards install を現在のプロジェクトで実行することを推奨します。これによって、shard.lock がいくつかの追加の新しいバージョンのフォーマットを持つことに気付くかもしれません。そして、lib/.shards.info ファイルがインストールした依存関係を説明するものとして追加されています。この新しいファイルはバージョン管理システムでトラックする必要はありません。

最後に、依存関係のバージョン指定で version: >= 1.0.0, < 2.0 のように複数の指定を交差させられるようになったことを紹介します。

このバージョンでの shards の完全な変更のリストはチェンジログを参照してください。

標準ライブラリ

このリリースにはいくつもの破壊的変更が含まれます。それらの大半は普通、非推奨の警告が出るようになっています。標準ライブラリの整理なしに1.0へと進むことはないつもりです。このような整理は以前にもあったはずです。これに優先順位を付けることは簡単ではなく、地道に進めています。

計算結果の出力や入力に IO を引数に取る多くのメソッドがあります。#5916 で、このような引数を最初の引数にすることを標準化する提案がありました。これは #9134 といくつかのそれに続く PR で実現されました。

これらのすべての IO メソッドに関係して、String クラスのメソッドで、String の値を返すものについて、値を返すのではなく結果を IO に書き込むようなオーバロードが追加されました。詳細は#9236を確認してください。この影響を受けるのは #underscore#titleize#capitalize#upcase、そして#downcase といったメソッドです。

文字列のインターポレーションの際に生成された文字列が直接 IO に渡されるようにするための改善の提案として、#9291に目を通しておくといいでしょう。

その他の IO の破壊的な変更としては、#skip#write#write_utf8#write_byte#write_bytes、や#skip_to_end がスキップした/書き込んだバイト数の数値を返すようになったことがあります。これは他の言語でもそのようになっており、書き込み中に追加の呼び出しなく現在のストリームを位置を把握できるようになります。詳細は#9233#9363を確認してください。

@[Experimental] アノテーションという、ライブラリや言語、shardの部分に細心の注意と共に使う必要のあるという指定をするためのものが導入されました。実験的な (experimental) 機能は変更や破壊、もしくは削除を Semver の規約に関わらず行なっても良いものとします。今のところ、アノテーションはドキュメントジェネレータで利用されています。ですが、他にも追加の機能のアイディアがあります。詳細は#9244を確認してください。

Digest 型がリファクタリングされて、いくつかのメソッドの名前が変更されたことに注意する必要があるかもしれません。詳細は#8426を確認してください。

さて、OptionParser がサブコマンドを定義できるようになりました。詳細は#9009を確認してください。

その他に整理したものとしては#8886で、FlateGzipZip、そしてZlibCompress モジュールに移動されました。また、FlateCompress::Deflate に名前が変更されています。require "compress/gzip" として、これらの定数を変更する必要があります。require "gzip" は依然として有効ですが、警告メッセージが表示されることになります。

いくつかの変更が FileFileUtils にあります。これらは整理されて、強制する操作が両方の API で有効になりました。詳細は#9175を確認してください。

マクロ

クロスコンパイルの際、host_flag? というマクロが追加されたことを知っておくと便利でしょう。これは flag? のようなものですが、ホストのマシンで解決されます。詳細は#9049を確認してください。

数値計算

符号付きと符号無しの数値の混ざった演算のオーバーフローの検出が修正されました。詳細は#9403を確認してください。

Int#digits というメソッドが追加されて、一貫性のため BigInt#digits の出力が反転されました。詳細は #9383 を確認してください。

シリアライズ

JSON.mappingYAML.mapping を使っている場合は、github:crystal-lang/json_mapping.crgithub:crystal-lang/yaml_mapping.cr に移行してください。これらの機能は十分なものでしたが、現在は JSON::SerializableYAML::Serializable がより良いものとしてあるため、標準ライブラリから削除されました。詳細は #9272 を確認してください。

時刻

これからは Time#to_rfc3339 のデフォルトの精度は秒となり、それ以上の精度は出力されません。より細かな精度が必要な場合は fraction_digits という名前付き引数に 0. 3, 6, 9 という精度の桁数を指定してください。#9283 で、時刻に応じて小数点以下の秒を表示する機能を削除しています。

ネットワーク

SSL サーバーのデフォルト値を#9026で更新しました。また、HTTP::Server が SSL ハンドシェイク中に時折失敗する問題を#9177で修正しました。

そして、HTTP::Serverに2つの破壊的な変更があります。エラーハンドリングとログまわりの処理を#9115で改善し、新しいログモジュールと統合しました。#9210で、HTTP::Request#remote_address の型を Socket::Address? に変更しました。

ログ

まず初めに、0.34.0で導入した新しいログモジールを早期に試してフィードバックを送ってくださった皆様に感謝いたします。破壊的な変更を含むいくつかの変更点がありますが、それらは主要な API には影響しません。これらを組み合わせることで、追加の機能といくつかのユースケースでのパーフォマンスの改善を達成しています。

#9293Log::Severity::WarningWarn へと名前を変更しました。Log.warn { ... } がありましたが、これはそのままで、警告を表します。。この変更は :warning やほとんどの環境変数経由での設定に影響します。同様に Verbose を削除して、TraceNotice#9107で追加しました。

ログのセットアップがよりシンプルになりました。Log.setup* 系の2つのメソッドがあります。これらのメソッドは常にソースとバックエンドの間のバインディングを完全に設定するでしょう。

Log.setup :debug # will show debug or above in the stdout for all source
Log.setup "db.*", :trace # will show trace or above in the stdout for db.* sources and nothing else
Log.setup_from_env # will grab the value of LOG_LEVEL env variable

Log.setup_from_env が1つの環境変数を受け取って動作するようになったことにも注意してください。より柔軟なものが今後追加されるかもしれませんが、名前付き引数はより良い体験を提供するはずです。詳細は#9145を確認してください。

各エントリはこれまでより、現在実行しているファイバーから取得したコンテキストの情報を持っていました。その Log::Context の責務を Log::MetadataLog::Metadata::Value に分割することにしました。前者はSymbol から Log::Metadata::Value へのハッシュのようなデータ構造ですが、アロケーションやアルゴリズム的な最適化がされています。これらは主に#9227#9295で実装されました。これらのリファクタリングによって、クローンによって獲得していた Log::Metadata::Value の不変性 (immutability) が無くなりました。

ログエントリにローカルのメタデータや構造化された情報を追加したいという機能が望まれていました。もちろん、現在のファイバのコンテキストに対する変更や復旧が最小であるものが望ましいです。エントリが出力されていない場合は値の生成を省略するという当初の設計を保って、これを達成しました。

Log.info { "Program started" }
Log.info &.emit("Program started") # same as previous
Log.info &.emit("User logged in", user_id: 42) # local data
Log.info &.emit("User logged in", expr_that_computes_hash_named_tuple_or_metadata)
Log.warn exception: e, &.emit("Oh no!", user_id: 42) # with exception
Log.warn exception: e, &.emit("Oh no!") # with exception, no local data
Log.warn(exception: e) { "Oh no!" } # same as previous
Log.info &.emit(action: "log_in", user_id: 42) # empty message

カスタムのログフォーマッタを作る方法は#9211で再検討されました。ブロックや Proc からフォーマッタを作る方法はまだ利用できますが、文字列から直接フォーマッタを定義するシンプルな方法を確認してみてください。

出力するログのエントリーをテストしたい場合、新しく追加された Log.capture というヘルパーが利用できます。詳細は#9201を確認してください。

並行処理

Concurrent::Future とトップレベルの delayfuturelazy を削除しました。これらを使い続けたい場合 github:crystal-community/future.cr shard を利用してください。詳細は #9093 を確認してください。

その他に#9097parallel マクロが削除されました。

1.0 以降に向けて、より堅牢で様々な利用に耐えうるもの開発したいと考えています。

ランタイム

Process#signal があるので Process#kill を非推奨としました。詳細は#9006を確認してください。

また fork も非推奨となりました。これはマルチスレッド環境では有効ではありません。この変更が問題である場合は、Process.fork はまだ利用できるのでそちらを使ってください。しかし、このメソッドはもはや公開された API ではありません。詳細は#9136を確認してください。

プラットフォーム

macOS ユーザーへ、10.15 (Catalina) で起こるいくつかの互換性の問題を#9296で修正しました。

BSD のユーザーヘ、DragonFly(BSD) のサポートを#9178で追加しました。

musl ユーザーへ、奇妙な segfaults が#9238で、バックトレースが空になる問題が#9267で修正されました。

Windows ユーザーへはたくさんのお知らせがあります。現在進行中の取り組みを見るには Wiki ページ#5430を確認してください。

今回のリリースでの Windows 向けの変更としては次のようなものがあります。

  • File の改善が#9015#9038#9037#9257で行なわれました。
  • IO の振舞いが#9207でアラインメントされました。
  • Process#9047#9021#9122#9112#9149#9310で実装されました。
  • crystal spec コマンドが Windows のパスで動作するように#9234で修正されました。
  • そして、コンパイラ自身を Windows 上でブートストラップできるようになりました。#9054#9062#9095#9106#9307

ですが、まだ標準ライブラリのすべての部分が Windows で利用できるというというわけではないことには注意してください。

ツール

主要な変更はドキュメントジェネレータで、バージョンピッカーをサポートするようになりました。外部に .json ファイルを用意して、現在と過去のリリースを指定することでバージョンピッカーに反映できます。詳細は#8792#9074、それと#9254を確認してください。

次のステップ

Crystal をアップデートしてください。そして、問題の報告を心待ちにしています。私たちは1.0.0に向けての開発を始めています。1.0.0-preX のようなリリースをして、最終的な調整を重ねていくでしょう。

ここ数回のリリースで修正が多かったことは認めます。ですが、不快感は最小になるように心掛けたつもりです。

すべての非推奨にした定義は1.0では削除される予定です。1.0をクリーンなバージョンにしたいと思っています。

84codesNikola Motor Company、そして大勢のスポンサーの継続的なサポートにたくさんの感謝をします。継続的に開発・メンテナンスを続けていくには、寄付が不可欠です。OpenCollectiveBountysource の2箇所で受け付けています。Crystal の直接のスポンサーになりたい場合や、他のサポート方法を探している場合は crystal@manas.tech に連絡してください。それでは、ここまで読んでいただきありがとうございます!