F# and F# tools update for Visual Studio 16.10(日本語訳)

8 min read読了の目安(約7200字

はじめに

この記事は F# and F# tools update for Visual Studio 16.10 の日本語訳となります。
主に情報として必要なものを取り上げている都合上、元の記事の内容を一部省略しています。
また、意訳・超訳・誤訳等が含まれている可能性もありますので、予めご了承ください。




F# and F# tools update for Visual Studio 16.10

Visual Studio 16.10 の F# tools のアップデートをアナウンスできて大変うれしく思っています。
今回のリリースでは2月にリリースした Visual Studio 16.9 から引き続き F# の開発体験を向上させるべく以下の機能改善に取り組んできました。

  • 外部シンボルへの「定義へ移動」機能の追加
  • C# と F# のプロジェクトを混在させた場合のサポート強化
  • クイックフィックスとリファクタリング機能の強化
  • F# tools のパフォーマンスと応答性の向上
  • コアコンパイラの改善




1. 外部シンボルへの「定義へ移動」機能の追加

これは 2016年 に機能リクエストがあってから、長期間開発が進められてきました。
そしてついにリリース日を迎えられました!

https://www.youtube.com/watch?v=56yqVkWS0BY

動画で紹介しているように F12キー を押下するか Ctrl + Click をすることで fsi が表示されます。
また、XML ドキュメントがある場合はそれも含めて表示されます。




2. C# と F# のプロジェクトを混在させた場合のサポート強化

Visual Studio 16.9 までは C# と F# のプロジェクトを混在させたソリューションを開発する場合、変更を反映させるためにプロジェクトをリビルドする必要がありました。
Visual Studio 16.10 からは C# のプロジェクトに変更を加えてもプロジェクトをリビルドする必要がなくなりました!

https://www.youtube.com/watch?v=zvuVPe11cGE

動画でわかるように、C# プロジェクトに変更を加えるとその変更が即座に F# プロジェクトへ反映されています。
ただ残念なことに現段階では F# プロジェクトの変更を C# プロジェクトに即時反映させることはできていません。


現状をまとめると以下のようになります。

  • ✅ C# プロジェクトへの変更はリビルドなしに F# プロジェクトへ反映されます
  • ✅ F# プロジェクト上で利用している C# プロジェクトで定義したものに対して「定義へ移動」をすると、実際の実装箇所へ移動してくれます
  • ❌ F# プロジェクトへの変更はリビルドしないと C# プロジェクトに反映されません
  • ❌ C# プロジェクト上で利用している F# プロジェクトで定義したものに対しての「定義へ移動」はまだできません

まだ対応できていない箇所については、現在実装を進めています。
これは非常にローレベルな開発であり、F# コンパイラから C# ツールまで変更を加える予定です。




3. XML ドキュメントのスキャフォールド

Visual Studio 2019 がリリースされてから今までの間、XML ドキュメントのスキャフォールド機能はパフォーマンス上の懸念から無効化されていました。
これは当時の実装では UI 遅延 (≒ 動作が重い感じ) の大きな原因となっていたためです。特に大量のメモリを使うシナリオと組み合わさったときに Visual Studio 全体に悪影響を及ぼす可能性がありました。

今回の 16.10 リリースまでに F# tools へ多くのパフォーマンス改善をし続け、XML ドキュメントのスキャフォールド機能の実装にも改良を施した結果、UI 遅延を発生させないことに成功しました。
そのため、16.10 からはこの機能をデフォルトで 有効 にしています!

https://www.youtube.com/watch?v=oNXSfoBeEnw&t=12s


4. クイックフィックスとリファクタリング機能の強化

前回のリリースに引き続き、さらなるクイックフィックスとリファクタリング機能を Visual Studio 16.10 に追加しています。


【クイックフィックス】未使用のバインディングを削除する提案

スコープ内で一度も使われていないバインディングがある場合に「削除」が提案されます。


【クイックフィックス】適切な不等号演算子を提案

C# などの他の言語を使っている人は慣れで不等号演算子に != を使ってしまい、エラーが出て混乱してしまうときがあります。
このクイックフィックスではそんなときに <> を使うように提案します。


【クイックフィックス】型が不確定なオブジェクトに型注釈を追加する提案

コンパイラがコンパイルできないコードにも関わらず、F# tools がコンパイラにできない型推論をしてしまい「エディタ上では警告・エラーが無いのにコンパイル時にエラーになる」というなんとも紛らわしい動作をすることがありました。
今回の修正によりコンパイラが実際に型推論できない場合には型注釈を追加するような提案をするようになります。


【リファクタリング機能】型注釈追加のリファクタリング機能

F# tools に初めてのリファクタリング機能を追加しました。
リファクタリング機能はクイックフィックスとは違い警告やエラーによって起動されるものではありません。
その代わり、カーソルの位置にあるコードにリファクタリング機能が適用できることを示す電球アイコン(💡)が表示されます。




4. F# tools のパフォーマンスと応答性の向上

これまでの数回にわたるリリースと同様、大規模なコードベースに対する F# tools のパフォーマンスと応答性の向上を図りました。


メモリ使用量の削減

Visual Studio のシンタックスハイライトは「分類(classification)」と呼ばれる処理の結果により色が付けられます。
「分類」は以下の2種類が実行されます。

  1. シンタックス分類
  2. セマンティクス分類


「シンタックス分類」ではキーワードと非キーワードの識別などが行われます。
型チェックを行わないため非常に軽い処理で済みます。
とても大きなファイルを開いたとき、型よりも先にキーワードへ色が付けられていくのはそういった理由です。


対して「セマンティクス分類」はクラス・構造体・列挙型・メソッド・プロパティなどを区別するため重い処理となります。
セマンティクス分類を行った結果、コードに対してシンタックス分類よりも細やかな色付けが行われます。ただしセマンティクス分類は言語サービスの最初のセマンティクス操作でもあるのでキャッシュもいっぱいになります。


セマンティクス分類で使用されるキャッシュの1つは、実際の分類情報そのものです。
今まではこの情報1つの大きな配列に格納してました。そのため時間とともにかなり多くのRAMを消費してしまうケースもありました。
今回のアップデートはここに対して修正をかけることによって最大200MBのメモリを節約できるようになりました。


この変更は Saurav Tiwary さん が行ってくれました。
ありがとうございます!


より多くのIDE機能のレスポンスが向上

前回のリリースから セマンティクス情報のリクエストを連続処理させないようにする改良 を F# 言語サービスへ加え始めました。
今回のリリースではリクエストを順番に処理するためのキューからさらに多くの操作項目を取り除きました。

これらの変更によって特に大規模なコードベースで入力に対する反応がさらによくなりました。

前回の改善についての日本語訳は こちら から確認してください。




5. コアコンパイラの改善

F# プロジェクトファイルで WarnOn 要素をサポート

特定のコンパイラコードを警告として出力したい場合、今までは .fsproj 内に OtherFlags 要素を利用して <OtherFlags>--warnon:1182</OtherFlags> のような記述をする必要がありました。
今回のリリースによって C# のように WarnOn 要素を利用して <WarnOn>1182</WarnOn> と記述できるようになりました。


この実装は Chet Husk さん が行ってくれました。
ありがとうございます!


ApplicationIcon のサポート

今回のリリース以前では .fsproj 内に ApplicationIcon 要素を設定しても何の意味もありませんでした。
本リリースによって ApplicationIcon が機能するようになります。
同時にコンパイラフラグとして --win32icon が追加されました。


この実装は albert-du さん が行ってくれました。
ありがとうございます!


Span の最適化

Jérémie Chassaing さん は Span/ReadOnlySpan のループに対するすばらしい最適化を実装してくれました。
以下のようなコードについて考えてみます。

let sumArray (vs: int ReadOnlySpan) =
   let mutable sum = 0
   for i in 0 .. vs.Length - 1 do
      sum <- sum + vs.[i]
   sum

このコードは境界チェックを取り除いたクリーンな IL を出力するようになり、ランタイムがループをより積極的に最適化できるようになりました。
この最適化は for x in xs do の場合にも適用されます。

○ 境界チェック についての補足
C# や F# は配列・コレクションにアクセスするときにインデックスがその配列・コレクション外を指し示していないかチェックをします。これを境界チェックと呼びます。
これは安全に配列・コレクションの要素へアクセスするために必要なのですがそのチェック分コストがかかります。
ループ処理の条件によっては確実に配列・コレクションの範囲内であることが保証されるパターンがあります。そういった場合にこの境界チェックをやらないように最適化できるとプログラムを高速化できます。




6. 今後について

今回のリリースで、公式に以下の3つの取り組みに対するサポートを強化する方針を固めました。

  1. .NET 6 での F# サポート強化
  2. .NET Interactive での F# サポート強化
  3. Visual Stuido 2022 での F# サポート強化


.NET 6 での F# サポート強化

近日中に (.NET 6 のリリースとともに) リリースする F# の言語機能を決定します。
今回はあまり多くの言語機能を追加するつもりはありません。それよりもコアコンパイラや F# Interacitve、Visual Studio の優先度が高いと考えています。
.NET 6 は LTS リリース なので、既存機能の完成度・パフォーマンス・信頼性を優先しています。
ただ、機能を追加しないと言っているわけではないということは付け加えておきます。
実際、ビルド時間を短縮するための コンパイラ機能 は 1~2 個リリースされる予定ですが、言語機能は F# 5 リリースのときと比べて少なくなる見込みです。


.NET Interactive での F# サポート強化

.NET Interactive で F# を使った開発を行う場合に「優れたアウトプット(テキスト・チャート)」や「優れたツール(インテリセンス・ツールチップ)」が提供され、幅広いライブラリ(特にデータサイエンスと機械学習向けのもの)を使うことで優れた開発体験が得られることに重きをおいています。
特にネイティブな依存関係にあるさまざまなパッケージを取り込むためのちょっと変わったパッケージレイアウトをサポートしています。
ただ、インテリセンスやツールチップなどのツール体験がすべてうまく機能するようにするためにやるべきことがまだ山積みとなっています。
.NET Interactive が GA されたあかつきには素晴らしい F# 体験を提供することをお約束します!


Visual Stuido 2022 での F# サポート強化

Visual Studio 2022 ではより素晴らしい F# 体験を提供することに重きをおいています。
Visual Studio 2022 は 64bit 化される予定なので、Visual Studio 2019 に比べてメモリ使用量が多くなります。
そのためパフォーマンス分析に多くの時間を費やしています。
プリビルド版では F# プロジェクトを読み込んで「すべての参照を検索」のような重い処理を走らせると、従来よりもメモリ使用量が約2倍となることを確認しています。
現在、このような要因を可能なかぎり低減することに取り組んでいます。また、Visual Studio を使っての開発による生産性向上のための機能強化についても実施しています(Inline Hint や C# との連携強化、ビルド時間の短縮など)。




期待して待っていてください!
楽しい F# コーディングライフを!