ほぼすべての最新のプログラミング言語(Go、Rust、Kotlin、Swift、Scala、Nim、Pythonの最終バージョンでも)で、型が常に変数宣言の変数名の後に来るのはなぜですか?
なぜx: int = 42
ありませんかint x = 42
?
後者は前者よりも読みにくいですか?
それは単なるトレンドですか、このソリューションの背後には本当に意味のある理由がありますか?
ほぼすべての最新のプログラミング言語(Go、Rust、Kotlin、Swift、Scala、Nim、Pythonの最終バージョンでも)で、型が常に変数宣言の変数名の後に来るのはなぜですか?
なぜx: int = 42
ありませんかint x = 42
?
後者は前者よりも読みにくいですか?
それは単なるトレンドですか、このソリューションの背後には本当に意味のある理由がありますか?
回答:
言及したすべての言語は型推論をサポートしています。つまり、型は、簡単に判別できる型を持つ初期化式を提供するときに十分にスマートであるため、それらの言語の宣言のオプション部分です。
式のオプション部分をさらに右に配置すると、解析のあいまいさが減り、その部分を使用する式と使用しない式の一貫性が向上するため、これは重要です。var
オプションのものに到達する前に、キーワードと変数名の両方が必須であることがわかっている場合、宣言を解析する方が簡単です。理論的には、コンピューターでの解析を容易にするこれらのすべてが人間の全体的な可読性を向上させるはずですが、それはもっと議論の余地があります。
次のようなC ++のような「非近代的な」言語が持っているすべてのオプションのタイプ修飾子、考えるとき、この引数は特に強い取得*
ポインタのため、&
、参照のためにconst
、volatile
というように。複数の宣言にカンマを挿入int* a, b;
するとb
、ポインターを作成しないなどの非常に奇妙なあいまいさが発生し始めます。
でもC ++は今の形で宣言「右のタイプ」をサポートauto x = int{ 4 };
し、それはいくつかの利点を持っています。
var
解析の簡素化の大部分を提供する、そのような必須キーワードの存在を認めたための+1 。
var
キーワードの存在は、名前優先表記法の目的に反しませんか?var userInput: String = getUserInput()
上書きの利点はありませんString userInput = getUserInput()
。利点userInput = getUserInput()
は、も許可されている場合にのみ関連しますが、それはスコープ変数の暗黙的な宣言を意味します。
var userInput = getUserInput()
またはauto userInput = getUserInput()
であるため、コンパイラgetUserInput()
は戻り値を知っているString
ため、型推論キーワードで指定する必要はありません。userInput = getUserInput()
もちろん、宣言する前に使用します。
ほぼすべての最新のプログラミング言語(Go、Rust、Kotlin、Swift、Scala、Nim、Pythonの最終バージョンでも)で、型が常に変数宣言の前にではなく後に来るのはなぜですか?
あなたの前提には2つの面で欠陥があります:
Pascal、ML、CLU、Modula-2、およびMirandaはすべて非常に影響力のある言語であったため、このスタイルの型宣言が普及したままであることは驚くことではありません。
なぜ
x: int = 42
ありませんかint x = 42
?後者は前者よりも読みにくいですか?
可読性は親しみの問題です。個人的には、中国語は読めないと思っていますが、中国人は読めないようです。学校でパスカルを学び、エッフェル、F♯、ハスケル、スカラに手を出して、TypeScript、Fortress、Go、Rust、Kotlin、Idris、Frege、Agda、ML、Ocamlなどを見て、それは私にとって完全に自然に見えます。
それは単なるトレンドですか、そのようなソリューションの背後にある本当に意味のある理由はありますか?
それがトレンドである場合、それはかなり持続的です:私が述べたように、それは数学で100年前に遡ります。
識別子の後に型を置くことの主な利点の1つは、推論させたい場合に型を簡単に省けることです。宣言が次のようになっている場合:
val i: Int = 10
次に、型を省略して次のように推論させるのは簡単です。
val i = 10
一方、次のようにタイプが識別子の前に来る場合:
Int i = 10
次に、パーサーが式と宣言を区別するのが難しくなり始めます。
i = 10
言語設計者が通常考え出す解決策は、タイプの代わりに記述しなければならない「タイプを記述したくない」キーワードを導入することです。
var i = 10; // C♯
auto i = 10; // C++
しかし、これは実際にはあまり意味がありません。基本的に、タイプを書かないと言うタイプを明示的に書かなければなりません。え?そのままにしておく方がはるかに簡単で賢明ですが、それによって文法がより複雑になります。
(そして、Cでの関数ポインター型についても話さないでください。)
前述の言語のいくつかの設計者は、この主題に重点を置いています。
宣言が逆向きなのはなぜですか?
Cに慣れている場合にのみ逆になります。Cでは、変数は型を表す式のように宣言されるという概念があります。結果は混乱する可能性があります。関数ポインタを検討してください。Goは式と型の構文をほとんど分離し、それによって物事を簡素化します(
*
ポインターにプレフィックスを使用することは、ルールを証明する例外です)。Cでは、宣言int* a, b;
a
ポインタであることを宣言しますが、ポインタではありませんb
。囲inでvar a, b *int
両方がポインターであることを宣言します。これはより明確で定期的です。また、
:=
短い申告書は、完全な変数宣言は、同じ順序を提示しなければならないと主張している:=
のでvar a uint64 = 1
と同じ効果があります
a := uint64(1)
また、構文は、式の文法だけではなく、型の明確な文法を持つことで簡素化されます。などのキーワードは
func
、chan
物事を明確にします。
なぜ型宣言が右側にあるのですか?
コードが読みやすくなると信じています。また、いくつかの便利な構文機能を有効にします。たとえば、型注釈は簡単に除外できます。Scalaもこれが問題ではないことを証明しています。
Javaとの大きな違いは、型注釈の構文に関係します。これは、Java の「
variable: Type
」ではなく「Type variable
」です。Scalaの接尾辞タイプの構文は、Pascal、Modula-2、またはEiffelに似ています。この逸脱の主な理由は、型推論に関係しています。これにより、変数の型やメソッドの戻り型を省略できることがよくあります。"variable: Type
"構文を使用すると、これは簡単です。コロンとタイプを省くだけです。しかし、Cスタイルの「Type variable
」構文では、型を単純にそのままにすることはできません。定義を開始するマーカーはもうありません。欠落している型のプレースホルダーとなる代替キーワードが必要になります(一部の型推論を行うC♯3.0はvar
、この目的に使用します)。このような代替キーワードは、Scalaのアプローチよりもアドホックで規則的ではないと感じます。
注:Ceylonの設計者は、プレフィックスタイプ構文を使用する理由も文書化しました。
接尾辞タイプの注釈の代わりに接頭辞
PascalとMLを宣言名の後に置くのではなく、なぜ型注釈を最初に置くのにCとJavaに従うのですか?
私たちはこれを考えるので:
shared Float e = .... shared Float log(Float b, Float x) { ... }
単にこれよりも読みやすいです:
shared value e: Float = .... shared function log(b: Float, x: Float): Float { ... }
そして、私たちは、他の人が他の方法で考えることができる方法を単に理解していません!
個人的には、彼らの「主張」は他の人よりも説得力が低いと感じています。
var
、auto
、let
型宣言がオンになっていない変数のどちら側によって、等。var Int x = 5
または、Int var x = 5
両方をに短縮することもできvar x = 5
ます。
"Your premise is flawed on two fronts"
これらのすべては、C#またはD.より新しい
func
Goとまったく同じ意味です。
ちなみに、Pascalもそれを行っており、新しい言語ではありません。しかし、それは最初から設計されたアカデミックな言語でした。
変数名から始める方が意味的に明確だと思います。タイプは技術的な詳細にすぎません。クラスを現実のモデルのように読みたい場合は、エンティティの名前を最初に、技術的な実装を最後に置くのが理にかなっています。
C#とjavaはCに由来するため、経験のあるプログラマを混乱させないために、「先行技術」を尊重する必要がありました。
なぜ
x: int = 42
ありませんかint x = 42
?後者は前者よりも読みにくいですか?
このような単純な例では、大きな違いはありませんが、もう少し複雑にしましょう。 int* a, b;
これは、Cでの実際の有効な宣言ですが、直感的には見た目どおりに動作しません。typeの2つの変数を宣言しているように見えますint*
が、実際には1つと1つint*
を宣言していますint
。
言語の宣言で変数名の後に型を置くと、その問題に遭遇することは不可能です。
x, y *int;
2 *int
または1 *int
と1 int
?作成int*
または*int
代わりに、二つのうちの一つのトークンは、それを解決するだろう、などの追加の構文要素使用して:
どちらの方向に働くことができ、。
:
またはなどの追加のトークンを使用しますas
。
x, y *int
「int-to-int型の2つの変数xとyを宣言する」ことを意味します。
int[] x, y
2つの配列として扱います。問題の原因となるのは、変数の単項演算子(およびプレフィックスとポストフィックスの組み合わせ)としてこれらの修飾子を扱うのは、愚かなC構文だけです。