Name before type: why 'age int' is better than 'int age'

Ben Hoyt

型より名前を先に:なぜ『age int』は『int age』より優れているのか

原文は Ben Hoyt により に公開されました。 このブログを購読する

要約:変数名は型よりも重要なので、宣言では名前をより目立たせ、先に書くべきです。

C、C++、Java、C#など、多くの人気のあるプログラミング言語では、フィールドや変数を定義する際に型を名前の前に書きます。例えばC++では次のようになります。

// Struct definition
struct person {
    std::string name;
    std::string email;
    int age;
};

// Stand-alone variables
std::vector<person> people = get_people();
int min_age = find_minimum_age(people);
std::string domain = parse_email_domain(people[0].email);

一方、Go、Rust、TypeScript、Python(型ヒントを使用する場合)などの言語では、名前を型の前に書きます。例えばGoでは次のようになります。

// Struct definition
type Person struct {
    Name  string
    Email string
    Age   int
}

// Stand-alone variables
var people []Person = getPeople()
var minAge int = findMinimumAge(people)
var domain string = parseEmailDomain(people[0].Email)

// Though it's more typical in Go to use := (short variable declarations)
people := getPeople()
minAge := findMinimumAge(people)
domain := parseEmailDomain(people[0].Email)

Go FAQには、なぜGoがこの順序を採用したのかについて分かりやすい回答があります。「なぜ宣言は逆順なのか?」という項目です。回答は「Cに慣れているから逆に見えるだけだ」という一文から始まりますが、これは的を射た指摘です――名前を先に書く方式はPascalのような言語にまで遡る長い歴史を持っています。実際、Goの型宣言の構文(そしてパッケージ)はPascalから直接影響を受けています。

FAQではさらに、名前を先に書く方式の方が構文解析がシンプルになることや、複数の変数を宣言する際にCよりも間違いが起こりにくいことも指摘されています。Cでは次のように書くと、xはポインタとして宣言されますが、(一見意外なことに!)yは通常の整数として宣言されます。

int* x, y;

一方、Goで同等のコードを書くと、期待通りに両方ともポインタとして宣言されます。

var x, y *int

Go BlogにはRob PikeによるGoの宣言構文についての詳しい記事もあり、Cの構文に対するGoの構文の利点、特に配列や関数ポインタにおける利点が詳しく解説されています。

不思議なことに、この記事では日常的なプログラミングにおいて名前を先に書く方式を推すべきより重要な理由については、ほのめかす程度にしか触れられていません。それは、単純により明確だからです。

変数名は型よりも重要なので、宣言では名前をより目立たせ、先に書くべきです。

これはいくつかの方法で簡単に示せると思います。

  1. 変数宣言における型推論の普及です。今やほとんどの言語に搭載されている機能で、var(C#やJava)、:=(Go)、auto(C++)などがそれにあたります。
  2. 動的型付け言語(PythonやRubyなど)の存在です。これらの言語ではそもそも型はまったく必要なく、あるのは名前だけです!
  3. 名前の方がより多くの意味を持っていることです。先ほどの例では、minAgeというだけで最小の年齢の値であることが明確にわかり、それがintであることを知っても情報はさほど増えません。もちろん型は型チェックには有用ですが、型が推論される場合でもコードは明確なままです。(英語でも型推論は使われています。「Person Ben Hoyt wrote this text article.」などとは普通言いませんよね。)

私は以前からこう考えていましたが、今回これを文章にしようと思ったきっかけは、最近リリースされたCap’n Proto 1.0でした。これを見て、Protocol BuffersCap’n Protoのスキーマ構文の違いを思い出したのです。

下のどちらの例でフィールド名を見つけやすいでしょうか。まずはProtocol Buffersのスキーマです。

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

あるいは、こちらのCap’n Protoの例ではどうでしょうか。

struct SearchResponse {
  results @1 :List(Result);
}

struct Result {
  url @1 :Text;
  title @2 :String;
  snippets @3 :List(Text);
}

どう感じるかは人それぞれかもしれませんが、私は最も重要な部分であるフィールド名が、Protocol Buffers版では少し埋もれてしまっていると思います。Cap’n Proto版では左揃えになっているおかげで、フィールド名がはっきりと見やすくなっています。

結論として言いたいのはこうです。過去は変えられませんが、もし新しい言語を作るなら、ぜひ名前を型の前に置いてください!

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。

コメント