Rakuはコンパイル時にどのタイプチェックを実行しますか?それは将来変わるかもしれませんか?

Aug 19 2020

現在(2020年8月現在)Rakudoはコンパイル時に関数の戻り値を型チェックしません。つまり、関数が戻り制約を満たすという静的な保証は提供されません。具体的には、次の2つの関数はどちらもRakuとしてコンパイルされます。

sub get-int(--> Int) { 'bug' }
sub get-int($a --> Int} { when $a == 5 { 'Rare bug' }
   default      { 42 }
}

関連する質問が2つあります。

  1. コンパイル時に現在どのようなタイプチェックが行われているのかを知る方法はありますか?(誰かが書いたリスト、ドキュメントのどこか、またはRakudoソースの中心的な場所のいずれかを介して)またはそれはそれよりもアドホックですか?

  2. このコンパイル時の欠如は、意図的な設計上の決定をタイプチェックしていますか?または、静的タイプチェックを追加して、いつかはあるといいのですが、まだ実装されていませんか?

(私は、Rakuの型/制約に対するパフォーマンスペナルティに対するJohnathanのすばらしい答えをよく知っていますか?、「Rakuは、プログラムに書き込まれた型制約が遅くとも実行時強制されることを義務付けています。」その答えは、実行を回避するさまざまな方法を説明しています。 -タイプチェックの時間コスト。ただし、コンパイル時にタイプチェックが実行される内容については説明されていません(これにより、実行時のコストが確実に回避されます)。

回答

12 JonathanWorthington Aug 19 2020 at 12:04

現在、コンパイル時に型のチェックはほとんど行われません。これは主に、静的オプティマイザーの副作用として発生します。今日のチェックは、主にサブルーチン呼び出しに関するものです。ここで、

  • 呼び出しのアリティを判断し、渡された引数の数が決して一致しないことを知ることができます
  • 文字通りの引数があり、署名と一致する可能性はないことがわかります

これは、静的オプティマイザがより多くのインライン化作業を行ったときの残り物です。最近では、コンパイル時にネイティブオペレーターのみをインライン化し、残りはVMの動的オプティマイザーに任せています。VMの動的オプティマイザーは、インライン化がはるかに可能で、インライン化も解除できます(投機的最適化を許可しますが、元のスタックトレースを復元できることも意味します。静的オプティマイザはこの情報を失いました)。

コンパイル時にさらに多くのことを行うことが望ましいと考えられていますが、考慮すべきいくつかの実際的な問題があります。

  1. 追加のチェックを導入すると、以前は機能していたコードが破損する可能性もあります。より厳密なコンパイル時チェックに失敗するコードパスを持つモジュールを検討してください。ただし、そのような場合に遭遇することのないシステムで使用されています。新しいバージョンのコンパイラでのコンパイルに失敗し始めた場合、コンパイラのアップグレード後にそのシステムをデプロイすることは不可能になります。一般に、これは、実行されるチェックが言語バージョンの変更時に変更される必要があることを意味します。(これは、コードを書くときに、書く言語バージョンを宣言する必要があることを意味します。)
  2. コンパイル時に実行されるチェックが増えると、「実行時のコストを確実に回避できる」というのは事実かもしれませんが、それを推論するのは簡単ではありません。マネージドランタイムは、与えられたバイトコードで行われた約束を盲目的に信頼することはできません。これは、メモリの安全性違反につながる可能性があるためです(SIGSEGV以下につながる可能性があります)。これは、型チェックのセマンティクスがプログラム可能なRakuのような言語では非常に明確に当てはまりますが、JVM、CLRなどでは当てはまります。Rakuでの最大の型関連の勝利は、ネイティブ型の使用によるものです。これにより、多くの割り当てを回避できるため、ガベージコレクション作業を回避できます。
  3. さらにチェックを実装すると、コンパイラの複雑さが増し、コンパイルに必要な時間が長くなります。これらの最初のものはすでに問題です。コンパイラのフロントエンドでは、約10年間でアーキテクチャに大きな変更はありません。マクロの基礎を築く現在のRakuASTの作業には、コンパイラフロントエンドのほぼ書き直しも含まれます。改善されたアーキテクチャにより、コンパイル時の型チェックの実装が容易になるはずですが、コンパイルの側面を並列化する方法についても検討されています。これにより、コンパイラは、ウォールクロックのコンパイル時間を増やすことなく、より多くのことを実行できます。

現在のコンパイラフロントエンドのオーバーホールが完了すると、コンパイル時のチェックがさらに導入される可能性が高くなります(ただし、次の言語バージョンからのみ有効になります)。少なくとも、誰かが作業している限りはそうです。

ただし、この分野ではさらにエキサイティングな機会が訪れます。RakuプログラムへのAPIがあり、カスタムコンパイラパスの計画がまとめられているため、まもなくタイプチェッカーをモジュールとして実装することも可能になります。それらのいくつかは、将来のRaku言語バージョンに組み込まれるチェックにつながる可能性があります。他のものは非常にドメイン固有であり、特定のモジュールのより正しい使用を可能にすることを目的としている場合があります。他の人は、基本言語の精神ではないが、一部の言語ユーザーがオプトインしたいと思うかもしれない厳格さを強制するかもしれません。