Go FAQ でこの質問に出くわしましたが、しばらくの間私を悩ませていたことを思い出しました。残念ながら、答えが何を目指しているのか、私にはよくわかりません。
ほとんどすべての非 C ライク言語では、次のように変数名の後に型を置くようです。
var : int
純粋な好奇心から、これはなぜですか?どちらかを選択する利点はありますか?
Go FAQ でこの質問に出くわしましたが、しばらくの間私を悩ませていたことを思い出しました。残念ながら、答えが何を目指しているのか、私にはよくわかりません。
ほとんどすべての非 C ライク言語では、次のように変数名の後に型を置くようです。
var : int
純粋な好奇心から、これはなぜですか?どちらかを選択する利点はありますか?
Keith Randall が言うように解析の問題がありますが、それは彼が説明しているものではありません。「それが宣言なのか式なのかわからない」ということは単に問題ではありません。とにかく全体を解析してあいまいさが解決されるまで、それが式なのか宣言なのかは気にしません。
コンテキストフリー パーサーを使用すると、型が変数名の前か後に来るかどうかは少しも問題になりません。重要なのは、型の仕様を理解するためにユーザー定義の型名を調べる必要がないということです。現在のトークンを理解するために、以前のすべてを理解する必要はありません。
Pascal 構文は文脈に依存しません。完全ではないにしても、少なくともこの問題を WRT してください。変数名が最初に来るという事実は、コロン区切りや型記述の構文などの詳細ほど重要ではありません。
C 構文は状況依存です。パーサーが型記述がどこで終了し、どのトークンが変数名であるかを判断するには、指定された識別子トークンが変数名であるか、変数名に寄与する単なる別のトークンであるかを判断できるように、以前のすべてを解釈しておく必要があります。タイプの説明。
C 構文はコンテキスト依存であるため、yacc/bison などの従来のパーサー生成ツールを使用して解析することは (不可能ではないにしても) 非常に困難ですが、Pascal 構文は同じツールを使用して簡単に解析できます。とはいえ、現在では C や C++ の構文にも対応できるパーサー ジェネレーターが存在します。適切に文書化されていないか、1.? リリースなど、私の個人的なお気に入りはKelbt です。これはバックトラッキング LR を使用し、セマンティックな「元に戻す」をサポートしています。
実際には、C および C++ のパーサーは通常手書きであり、再帰的な降下と優先順位の解析が混在しています。同じことが Java と C# にも当てはまると思います。
ちなみに、C++ 構文解析でのコンテキスト依存性に関する同様の問題は、多くの厄介な問題を引き起こしました。C++0xの "代替関数構文" は、型指定を最後に移動し、区切り記号の後に配置することで、同様の問題を回避しています。これは、関数の戻り値の型の Pascal コロンと非常によく似ています。コンテキストの依存性がなくなるわけではありませんが、Pascal に似た慣習を採用することで、少し扱いやすくなります。
あなたが話す「他のほとんどの」言語は、より宣言的な言語です。それらは、あなたが考える線に沿ってより多くのプログラムを作成できるようにすることを目的としています (命令型の思考に縛られていないと仮定して)。
type last は、「TYPE TYPE の NAME という変数を作成する」と読み取ります。
これはもちろん「名前という名前のタイプを作成する」と言うのとは逆ですが、考えてみると、値が何のためのものであるかはタイプよりも重要であり、タイプは単にデータに対するプログラム上の制約です。
変数の名前が列 0 から始まる場合、変数の名前を見つけやすくなります。
比較
QHash<QString, QPair<int, QString> > hash;
と
hash : QHash<QString, QPair<int, QString> >;
典型的な C++ ヘッダーがどれだけ読みやすくなるか想像してみてください。
タイプをまったく記載しないか、任意でタイプを記載する傾向が強まっています。これは、変数に実際には型がない動的型付け言語である場合もあれば、コンテキストから型を推測する静的型付け言語である場合もあります。
型が時々与えられ、時には推論される場合、オプションのビットがその後に来ると読みやすくなります。
ある言語が C 学派や機能学派などから来ていると見なすかどうかに関連する傾向もありますが、これらは時間の無駄です。前任者を改善し、学ぶ価値のある言語とは、機能の継承についてうるさくするのではなく、メリットに基づいてあらゆる異なる流派からの入力を喜んで受け入れる言語です。
形式言語論や型論では、ほとんどの場合、 と書かれていvar: type
ます。たとえば、型付きラムダ計算では、次のようなステートメントを含む証明が表示されます。
x : A y : B
-------------
\x.y : A->B
私はそれが本当に重要だとは思いませんが、2 つの正当化があると思いますint
。の整数) であり、表記は "x ε A" に関連しています。
このようなもののいくつかは、あなたが考えている現代言語よりも前のものです。
「過去を思い出せない者は、それを繰り返す運命にある。」
変数の前に型を配置することは、Fortran と Algol では問題なく開始されましたが、C では、いくつかの型修飾子が変数の前に適用され、他の型修飾子が後に適用されるため、非常に見苦しくなります。そのため、C には次のような美しさがあります。
int (*p)[10];
また
void (*signal(int x, void (*f)(int)))(int)
そのような意味不明なものを解読することを目的とするユーティリティ (cdecl) と一緒に。
Pascal では、型は変数の後に来るので、最初の例は次のようになります。
p: pointer to array[10] of int
対比
q: array[10] of pointer to int
これは、C では
int *q[10]
C では、これを int (*p)[10] と区別するために括弧が必要です。順序のみが重要な Pascal では、括弧は必要ありません。
信号関数は次のようになります
signal: function(x: int, f: function(int) to void) to (function(int) to void)
まだ一口ですが、少なくとも人間の理解の範囲内です。
公平を期すために言えば、問題は C が名前の前に型を置くことではなく、名前の前に断片を置き、他のものを名前の後に置くことをひねくれて主張することです。
しかし、名前の前にすべてを置こうとすると、順序はまだ直感的ではありません。
int [10] a // an int, ahem, ten of them, called a
int [10]* a // an int, no wait, ten, actually a pointer thereto, called a
したがって、答えは次のとおりです。適切に設計されたプログラミング言語は、結果が人間にとってより読みやすいため、変数を型の前に置きます。
それはまさに言語がどのように設計されたかです。Visual Basic は常にこの方法でした。
ほとんどの (すべてではないにしても) 中括弧言語は、型を最初に置きます。同じ位置でメソッドの戻り値の型も指定されるため、これは私にとってより直感的です。したがって、入力は括弧に入れられ、出力はメソッド名の後ろに出ます。
よくわかりませんが、「名前対名詞」の概念に関係していると思います。
基本的に、型を最初に置くと (「int varname」など)、「'varname' という名前の整数」を宣言することになります。つまり、型のインスタンスに名前を付けています。ただし、最初に名前を入力してから型 (「varname : int」など) を入力すると、「これは 'varname' です。整数です」ということになります。最初のケースでは、何かのインスタンスに名前を付けています。2 番目では、名詞を定義し、それが何かのインスタンスであると述べています。
これは、テーブルを家具として定義する場合に少し似ています。「これは家具で、私はそれを「テーブル」と呼んでいます」(最初にタイプ) と言うのは、「テーブルは一種の家具です」(最後にタイプ) と言うのとは異なります。
私はいつも、C のやり方は少し独特だと思っていました。型を構築する代わりに、ユーザーは型を暗黙的に宣言する必要があります。変数名の前後だけではありません。一般に、型属性の間に変数名を埋め込む必要がある場合があります (または、いくつかの使用法では、実際に変数を宣言する場合に名前がある場所に空のスペースを埋め込む必要があります)。
パターンマッチングの弱い形式なので、ある程度は理解できますが、特別な利点もないようです。また、関数ポインター型を書き込もう (または読み込もうとする) と、理解できる範囲を簡単に超えてしまう可能性があります。したがって、全体として、C のこの側面は不利な点であり、Go がそれを取り去ったことを嬉しく思います。
Fortran は型を最初に置きます。
REAL*4 I,J,K
INTEGER*4 A,B,C
はい、Fortran に詳しい人向けの (非常に弱い) ジョークがあります。
これは、型が十分に複雑な場合 (たとえば、関数へのポインター) に名前の周りに型情報を配置する C よりも簡単であると主張する余地があります。
型を最初に置くと、解析に役立ちます。たとえば、C で次のように変数を宣言したとします。
x int;
だけを解析すると、x
x が宣言なのか式なのかわかりません。とは対照的に
int x;
を解析するint
と、宣言の中にいることがわかります (型は常に何らかの宣言を開始します)。
言語の構文解析が進歩したことを考えると、このわずかな助けは、今日ではあまり役に立ちません。
動的に(乾杯 @wcoenen) 型付けされた言語はどうですか? 変数を使用するだけです。