Build Insiderオピニオン:岩永信之(1)
オープンソースのC#/Roslynプロジェクトで見たこと、感じた教訓
日本を代表する「C#(でぐぐれ)」の人、岩永信之氏によるコラムが遂に登場。今回はオープンソースで開発が行われているC#と開発者の関わり方について。
本日はRoslynについての話をしていきたい。Roslynは、オープンソースで開発されている新しいC#とVisual Basicのコンパイラーである。“Roslyn”という名称はコードネームで、最終的な製品名は.NET Compiler Platformとなった。
製品名が決まった一方で、GitHubのリポジトリ名はRoslynのままとなっている。これが、本稿のタイトルに「Roslyn」という言葉を残した理由である。つまり、本日の主題はオープンソース化され、GitHub上で公開されている「Roslynプロジェクト」自体の話である。
Roslynプロジェクトがオープンソース公開されたのが2014年の4月ごろで、1年半ほどの時間が経過した。本稿では、その1年半を見てきて、印象に残った流れや、そこから筆者が感じた教訓などについての話をしていきたい。
Roslynのオープンソース開発体制
Roslynに限らず、ここ数年のマイクロソフトはオープンソース開発に積極的である。製品ごとに程度の差はあるものの、開発ツール系の製品は早い段階からオープンソース化が進んでいた。Roslynは、ASP.NETなどのWeb系のツールと比べると遅かったものの、マイクロソフト全体から見ると比較的早い部類だろう。
このオープンソース化の流れについて、マイクロソフトの.NETチームは「クロスプラットフォームを持続可能な形で実現する最良の方法」と説明している。また、適用範囲が広がり、コミュニティが活性化することで、既存顧客にとっても大きなメリットになるだろうことを期待している。
オープンソース開発といっても、開発体制はプロジェクトごとに千差万別だろう。Roslynでは、「優しい独裁者」(benevolent dictatorship)統治モデルを採る。つまり、C#の言語設計に関する最終的な意思決定は、.NETチーム内の限られた少人数によって行われる。長期的にC#を魅力的で一貫性のある言語に保ち続けるためには集権的な強いリーダーシップが必要である。まれに「全然意見聞いてくれない」などというひがみも散見されるが、船頭多くして船山に上るよりはマシだろう。
オープンソースなC#との関わり方
オープンソースプロジェクトとの関わりは人それぞれだろう。コンパイラーというものに対して、ソースコードを書いて貢献しよう(あるいは、貢献できる)という人はそう多くないかもしれない。もっとも、規模や難易度によらず、コードを書いて貢献する人は少数派だ。
とはいえ、貢献の方法はいくらでもある。簡単かつ貢献度が高いのは、早い段階から使ってみてフィードバックを返すことだろう。C#チームのように長年仕事としてコンパイラーを作っている方々に意見するなんて釈迦(しゃか)に説法と思うかもしれないが、意外と抜けている部分があったりするものだ。また、逆に、「自分が出した案に何か穴があれば専門家が埋めてくれる」くらいの気持ちでいればいいだろう。最終的な責任はあくまでC#チームが持っている。
具体的な事案をいくつか見てみよう。
using static: 便利さばかりに目がいく
最初の事案として、C# 6.0で追加された機能の1つであるusing static
にまつわる話をしよう。クラスの静的メソッドを修飾なしで(グローバル関数のような直接的な書き方で)呼び出せるようにする機能である。
この機能、最初に提案されたころの構文では、using
の1単語だけを使っていた。つまり、名前空間に対するusing Namespace;
というような書き方同様、using ClassName;
だけでよかった。例えば以下のような書き方ができた。
using System.Console; // 今はusing static System.Console;
using System.Math; // 今はusing static System.Math;
class Program
{
static void Main(string[] args)
{
WriteLine(2 * Asin(1));
}
}
|
「using static ClassName;」ではなく「using ClassName;」だけでよかったのだが……
これに対して、using static ClassName;
というように、2単語に変えたいという計画は当初からあったものの、賛否両論あり、なかなか決断されずにいた。using
の1単語だけの方が書きやすく、便利そうだからである。
そんな中、以下のような悪用コードが書けることを発見してしまう。
using System;
using System.Linq; // 下の方で定義している方のLinqクラスが優先される
public class Program
{
public static void Main()
{
var name = nameof(Main); // System.Linq.nameofメソッドが呼ばれる
Console.WriteLine(name);
}
}
namespace System
{
public static class Linq
{
public static string nameof(Action x) => "";
}
}
|
System.Linq
名前空間を偽装する、System.Linq
クラスを作ってしまうという悪意あるコードだ。なおひどいことに、nameof
演算子の挙動を上書きするnameof
メソッドまで定義している。このコードを見せれば「static
要らない派」もさすがにあきらめてくれるだろう。そのくらいに大問題のコードである。
しかし、こんな悪夢のような悪用コードも、発見されるまでに結構な時間がかかっている。最初にusing static
構文の案が出たのは2013年末なのに対して、この悪用コードを思いついたのは2014年末だ。それまでの1年近く、C#チームの態度も「たぶん、static
を付けるのを必須にすると思うけれども……」くらいの自信ないものだった。
この件から得られる教訓は、人間誰しも便利さの方に目が行きがちということだろう。便利さの発明よりも、その裏に潜む問題の発見の方が往々にして多くの人数と時間を必要とする。
ちなみにこの問題は、名前空間に対するusing
だけがある言語に、後からクラスのusing
を足そうとしたから問題になったという面も否定はできない。ただし、C# 1.0からusing static
を入れていたとしても、名前空間と同名のクラスを後から追加できる以上、解決はなかなか難しいだろう。
文字コード: アーリーアダプターは気付かない
当然ではあるが、いわゆるASCIIコード圏の開発者にとって多言語対応は抜けがちで、よく不具合を起こす。Roslynもその例にもれず文字コードがらみの不具合があり、かつ、リリース後に発覚した。以下のような不具合対応が行われた。
問題は、リリースされるまでこの不具合が残ったという点である。
元をたどるとこの不具合は、次のリンク先のように、.NET Core対応のためにEncoding.Default
プロパティ(=OSの言語設定から既定のエンコーディングを取り出す)の利用を辞めたことに起因する。
日付的には3月末ごろのもので、その後、Visual StudioのRTM(リリース)前に、ベータ版やRC(リリース候補)版が数度出ている。この間、実は、Shift_JISで保存された日本語C#ファイルはコンパイルできなくなっていた。
実は、筆者はRC版の時点で一度この不具合を踏んでいる。最近のVisual Studioは日本語ソースコードを自動的にUTF-8で保存してくれるのだが、.NET登場最初期のVisual StudioはソースコードをShift_JISで保存していた。そのころに書いたソースコードを久しぶりにビルドし直してみる機会が筆者にはちょうどあったのだ。このときに不具合を報告しなかったから、RTM版にまで問題が残ったことになる。
不具合報告しなかった理由は単純で、「今時Shift_JISなソースコードを使っている方が悪い」と判断したからである。しかし結局は、リリース後に不具合とされ、急きょ修正される流れとなった(ただし、リリース後最初に騒がれたのは日本語ではなく中国語である。Shift_JISというより、UTF-8でない非ASCII文字全般に関する問題だった。ちなみに、欧米では4月の時点で不具合扱いされ、ほぼ即座に対応が入っている)。
ここでの教訓は、いわゆるアーリーアダプターと一般的な開発者の間には問題意識の差があるということだろう。「Shift_JISが悪い」はいかにもアーリーアダプターになるような人間の発想だ。このように、一般的な広い範囲の開発者に使ってもらわないと不具合として認識されないものがある。
しかしながら、わざわざ英語ページを読む苦労までして人柱になってくれる人がどのくらいいるのかという悩ましさもある。オープンソース化以前から、「日本人はリリースされてから文句を言う」などと、ある意味恐れられている。これも「言葉の壁」かもしれない。
private protected: 最終的な意思決定
中には、歴史的経緯などがあり、どうあがいても今からでは納得のいく提案ができないこともある。ここではC# 7.0向けに提案されているprivate protected
修飾子を例にとってみよう。
その前に、現状のC#で使えるアクセス制御用の修飾子についてあらためて紹介しておこう。
- public: どこからでもさわれる
- protected: クラス自身の中と、派生クラスの中からさわれる
- private: クラス自身の中からだけさわれる
- internal: 同じアセンブリ内のクラスからさわれる
- protected internal(語順は自由で、
internal protected も可):protected
またはinternal
な範囲からさわれる
この説明からprivate protected
の意味するところを想像できるだろうか。「private
またはprotected
」? 何それ?(「private
またはprotected
」だと、protected
と同じ意味にしかならない)
正解は、
- private protected:
protected
かつinternal
な範囲からさわれる
である。つまり、Figure 1に示す位置にくる。
分かりづらい……
一応、合理的な説明もある。private protected
の制限度合は、private
よりは緩く、protected
よりは厳しくなる。「,」(コンマ)と「.」(ピリオド)の間くらいの強さの句読点を「;」(セミコロン)と書くようなものである。えっ? でも、protected internal
はprotected
よりもinternal
よりも緩いけども……
そもそもの問題は、その昔、protected internal
を「protected
またはinternal
」の意味で使ってしまったことにある。C#の文法上、例えばpublic static
ならば「public
かつstatic
」、protected sealed
ならば「protected
かつsealed
」である。「または」になるのはprotected internal
だけだ。
当然、議論は紛糾する。そして、どの案も決定打に欠いている。例えば以下のような案が出たりした。
- assembly: 意味合い的にはほぼ
internal
の同義語で、internal
との区別が分からない - family: 同上
- protectedandinternal: 他にこんな複数単語を連結したキーワードがなく、浮く。あと、長い
- protected & internal: C#は、修飾子をつなぐのに記号を使える文法じゃない
- proternal: 面白い造語だけど、「または」なのか「かつ」なのか分からない問題を解消していない
これだけ決め手に欠けると、なかなか結論に至れないものである。恐らく、「過半数をもって可決」とかやっていたら最後まで決まらないような問題だ。しかし、前述の通り、Roslynプロジェクトは優しい独裁者制である。こういうまとまらないときこそが独裁者たる.NETチームの出番だ。.NETチームは今のところ「良い対案もないし、当初の予定通りprivate protected
にしたい」という判断を下している。「private protected
って何だよ」とFAQを聞かれるたびに、.NETチームが説明責任を果たしてくれるだろう。
教訓としては、世の中には負け戦になると分かっているものもあり、その責任を取るのもリーダーの役目なのだろう。ただ、決断までの過程がオープンになったことで、ずいぶんと納得感があり、C#チームに代わってここで筆者が説明することもできる。中身が見えるというのは大事なことである。
まとめ
Roslynプロジェクトのオープンソース化からの1年半を見てきた中から、印象に残った流れをいくつか紹介した。
- 便利さばかりに目がいくもので、その裏にある問題の発見には人数も時間も必要
- アーリーアダプターでは気付きにくい問題もあるのでより広い人の協力がほしい
- 人が増えても決めかねるものは決めかねるけど、そこは.NETチームがリーダーシップ発揮してくれるはず
使ってみて、フィードバックを返すことがオープンソースへの簡単、かつ、大きな貢献となるので、ぜひとも早い段階から新しいC#を試してみてほしい。フィードバックは些細なものでも十分だし、最終的な取りまとめは.NETチームに任せられるので、気軽に行えばいいだろう。
岩永 信之(いわなが のぶゆき)
※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
1. 【現在、表示中】≫ オープンソースのC#/Roslynプロジェクトで見たこと、感じた教訓
日本を代表する「C#(でぐぐれ)」の人、岩永信之氏によるコラムが遂に登場。今回はオープンソースで開発が行われているC#と開発者の関わり方について。
2. 次期C# 7: 式の新機能 ― throw式&never型/式形式のswitch(match式)/宣言式/シーケンス式
C# 6が出てまだ間もないが、すでに次バージョン「C# 7」についての議論が進んでいる。その中で提案されている「式」に関する新機能を取り上げる。
3. 次期C# 7: 複数データをまとめるための言語機能、タプル型
メソッドが複数の値を戻す場合など、複数のデータを緩くまとめて、扱いたい場合はよくある。C#の次バージョンではこれを簡潔に記述するための機構として「タプル型」が導入される。
4. 次期C# 7: 型に応じた分岐や型の分解機能、パターンマッチング
オブジェクトの型を階層的に調べて分岐処理を行いたい場合がある。そのための機能として、C#の次バージョンでは「パターンマッチング」が追加される。