なぜ変数名が数字で始められないのですか?


136

私はしばらく前に新しいC ++開発者と一緒に作業していたとき、「なぜ変数名は数字で始められないのですか?」

一部の数値にテキストを含めることができること(123456L、123456U)を除いて、答えを思い付くことができませんでした。コンパイラがアルファ文字を含むすべてを変数名であると考えていた場合、それは不可能です。

それは正解でしたか?他に理由はありますか?

string 2BeOrNot2Be = "that is the question"; // Why won't this compile?

15
そして、なぜ彼らは彼らの中にスペースを持つことができないのですか?
Tim

4
この問題は、最初のマクロアセンブラに戻っていない場合でも、C ++よりも少なくとも20年前に存在します。
Ken Gentle

2
まあ、FORTHでは、それを行うことができます。私の知る限り、0スタックに0をプッシュするという単語があります。もう1つは0=、0がスタックにあるかどうかを確認することです。
インゴ

12
なぜこの質問はそれほど人気が​​あり、答えはそれほど間違っているのですか?多くの言語では、変数を数字で始めることができます。C ++はそうではありませんが、特定のあいまいさを回避する便利な制限にすぎません。時々SOは私をあらゆる間違った方法で驚かせます。
david.pfx 2014年

5
この質問が今日SOで行われた場合、オピニオンベースと呼ばれ、締めくくられます。これを聞いてくれてありがとう。
ブーン2015年

回答:


116

なぜなら、数字の文字列は有効な識別子であると同時に有効な番号でもあるからです。

int 17 = 497;
int 42 = 6 * 9;
String 1111 = "Totally text";

37
まあ、変数が数字だけではいけないと言ったらどうでしょう。じゃあ何?
Pyrolistical 2008

6
可能であれば、そのルールを使用してレクサーが識別子を取得するための正規表現を思い付くのに時間がかかります。そのため、以下の理由に加えて、言語がそのように実装されていない理由を確認できます。他の答え。
skiphoppy 2008

39
数値+アルファでなければならない場合でも、String 0x123 = "Hello World"を実行できます。変数名が「数値+有効な数値指定に解析されないアルファ」であると述べていない限り、それはばかげています。
eaolson、2009年

4
コンパイラを気にする必要はありません。言語を使用する人々は、変数名と数値を(一目で)簡単に区別できる必要があります。最初の文字が教えてくれなかった場合-代わりに、単語の残りの部分を検索して、そこに数字以外のアルファベットがあるかどうかを知る必要がある場合-コードは読みにくくなります。
2012年

10
@eaolson:私はその規則をA- で始まり、Fで終わる16進数に適用するアセンブラを使用しましたh。バッハの2部発明#13(論理名?Bach)の音楽データを指すようにラベルを定義しようとしたとき、初めて私をつまずかせました 。
スーパーキャット2012年

116

これについてよく考えてください。

int 2d = 42;
double a = 2d;

何ですか?2.0?または42?

ヒント、取得できない場合、数値の後のdは、二重リテラルになる前の数値を意味します


11
これは、実際には[比較的]遅い表記( "d"の "d")、C89標準IIRCです。この構成が言語内にある場合、識別子の先頭の数値は使用できませんが、数値が識別子を開始できないのはそのためではありません。
Ken Gentle

1
dC ++では、有効な浮動リテラルサフィックスではありません。浮動リテラルは、デフォルトでダブルスは、あなたが使用することができますfまたはlあなたがfloat型またはlong doubleのリテラルが必要な場合。
CBベイリー

1
これはJavaに関するものであり、元々の質問はC ++に関するものでしたが、Javaのような他の多くの言語にも当てはまります。しかし、私は同意します。これは、識別子が数字で始めることができない元の理由ではありません。
Pyrolistical 2008

50

現在は慣例ですが、技術的な要件として開始されました。

昔は、FORTRANやBASICなどの言語のパーサーはスペースを使用する必要がありませんでした。したがって、基本的に、以下は同じです。

10 V1=100
20 PRINT V1

そして

10V1=100
20PRINTV1

ここで、数字のプレフィックスが許可されたと想定します。これをどのように解釈しますか?

101V=100

なので

10 1V = 100

またはとして

101 V = 100

またはとして

1 01V = 100

それで、これは違法にされました。


1
マイナーNIT:行番号、列1-6にしなければならなかった、および実行可能なコードは、一方の列8を次のDO 10 I=1,50曖昧として解析することができるDO1 0I=1,50なお、いずれかを使用代わりにコンマの期間場合、文はに割り当てとなります[という名前の浮動小数点変数DO10I
スーパーキャット

興味深い説明!それはまだ我々はまだPythonやJavaScriptやR.のような言語のための設計上の選択を続けてきた理由は、私は思ってしまう、古い言語のための理にかなっている
チャールズ・クレイトン

私はBASICでこれを間違いなく覚えており、これがおそらく実践の最も有効な実践的な理由だと思います。技術的には、私はそれが実際に初期のアセンブリ言語に戻る可能性があることを漠然と覚えています。しかし、アセンブラがどのようなものかわからないので、間違いなく間違っている可能性があります。
ブライアンチャンドラー

42

コンパイル中の字句解析ではバックトラックが回避されるためです。次のような変数:

Apple;

コンパイラーは、文字「A」に遭遇すると、それがIDであることをすぐに認識します。

ただし、次のような変数:

123apple;

コンパイラは、 'a'に到達するまで数値か識別子かを判断できず、結果としてバックトラックが必要になります。


2
私のコンパイラ設計クラスを思い出して答えるには、この答えは正解です!賞賛
nehem

15

コンパイラー/パーサー/字句アナライザーは私にとってかなり昔のことでしたが、コンパイル単位の数字がリテラルと識別子のどちらを表しているのかを明確に判断するのが難しいことを覚えていると思います。

スペースが重要でない言語(私が正しく覚えていれば、ALGOLや元のFORTRANのように)は、そのため、識別子を開始するための数字を受け入れることができませんでした。

これはずっと前に戻ります-ストレージまたは数値ベースを示す特別な表記法の前。


9

識別子を数字で始めることができるようにすると便利だと私は同意します。識別子の前にアンダースコアを追加することでこの制限を回避できると1人か2人が述べましたが、それは本当に醜いです。

問題の一部は、0xdeadbeefなどの数字リテラルに起因するものだと思います。これにより、数字で始まる可能性のある識別子のルールを簡単に覚えることが難しくなります。これを行う1つの方法は、[A-Za-z _] +に一致するもので、キーワードまたは数値リテラルではないものを許可することです。問題は、0xdeadporkは許可されているが、0xdeadbeefは許可されていないなどの奇妙なことにつながるということです。結局、私はすべての肉に公平であるべきだと思います:P。

私が最初にCを学んだとき、変数名の規則は恣意的で制限的であると感じました。最悪の場合、覚えるのが難しかったので、習得を諦めました。私はちょうど正しいと感じたことをやった、そしてそれはかなりうまくいった。私はもっ​​と多くを学んだので、それはそれほど悪くないと思われ、そして私は最終的にそれを正しく学ぶようになりました。


8
笑-「問題は、0xdeadporkのような奇妙なことが許可されるが、0xdeadbeefは許可されないことです。結局、私はすべての肉に公平であるべきだと思います:P」
mr-euro、

6

トークンを解析するときに、最初の文字を調べて、それが識別子であるかリテラルであるかを判断し、それを処理のために正しい関数に送信する必要があるのは、おそらくいくつかの理由から来た決定でしょう。これがパフォーマンスの最適化です。

もう1つのオプションは、それがリテラルでないかどうかを確認し、識別子のドメインをユニバースからリテラルを差し引いたままにすることです。しかし、これを行うには、すべてのトークンのすべての文字を調べて、それを分類する方法を知る必要があります。

識別子はニーモニックであることになっているため、文体上の意味もあるので、数字よりも単語のほうがはるかに覚えやすくなります。元の言語の多くが次の数十年間スタイルを設定して書かれていたとき、彼らは "to"を "2"に置き換えることを考えていませんでした。


6

変数名を数字で始めることはできません。以下のような問題が発生する可能性があるためです。

int a = 2;
int 2 = 5;
int c = 2 * a; 

cの値は何ですか?4、または10です。

もう一つの例:

float 5 = 25;
float b = 5.5;

最初の5は数値、またはオブジェクト(。演算子)は2番目の5にも同様の問題があります。

多分、他のいくつかの理由があります。したがって、変数名の先頭に数字を使用しないでください。


識別子に数字以外の文字が少なくとも1つ含まれている必要がある場合でも、文字を含む数値形式には英数字以外の文字も含まれている必要があります[たとえば、0x1234を$ 1234として記述し、1E6を記述する必要があります。 1.E6または1.0E6]として、またはそうでなければ、正当なID名と不正なID名の奇妙な組み合わせがあります。
スーパーキャット2013年

4

変数名の先頭に数字を使用すると、コンパイルまたは解釈中のエラーチェックが非常に複雑になります。

数字のように始まる変数名の使用を許可すると、言語設計者に大きな問題を引き起こす可能性があります。ソースコードの解析中に、コンパイラ/インタープリターが、変数名が予期されている数字で始まるトークンを検出した場合は常に、トークンが本当に変数であるかエラーであるかを判断するために、巨大で複雑なルールセットを検索する必要があります。 。言語パーサーに追加された複雑さは、この機能を正当化しない場合があります。

私が覚えている限り(約40年)、変数名の先頭に数字を使用できる言語を使用したことはないと思います。これは少なくとも一度は行われたと確信しています。多分、ここの誰かが実際にどこかでこれを見たことがあります。


1
それほど難しいことではありません。それは語彙フェーズをより難しくします、それだけです。もちろん、コンパイラを使用したときは、字句スキャンがコンパイル時間全体の4分の1を占める可能性があると言われました。
David Thornley、

4

いくつかの人が気づいたように、変数名の有効な形式については多くの歴史的な手がかりがあります。言語デザイナーは常に、新しい言語を作成するときに知っていることに影響を受けます。

そうは言っても、言語が変数名を数字で始めることを許可していない場合のほとんどは、それらが言語設計の規則だからです。多くの場合、そのような単純なルールにより、言語の解析と字句解析が非常に簡単になるためです。しかし、すべての言語デザイナーがこれが本当の理由であることを知っているわけではありません。最新の字句解析ツールが役立ちます。許容できるものとして定義しようとすると、解析の競合が発生するからです。

OTOH、あなたの言語が変数名を告げる一意に識別可能な文字を持っている場合、それらが数字で始まるように設定することが可能です。同様のルールのバリエーションを使用して、変数名にスペースを含めることもできます。しかし、結果として得られる言語は、一般的な一般的な言語とはまったく似ていないかもしれません。

変数が数字で始まり、スペースが埋め込まれていることを許可するかなり単純なHTMLテンプレート言語の例については、Qomposeをご覧ください


1
実際、識別子をマークする文字を持つことができるいくつかの言語があります。それらは「sigils」と呼ばれ、PerlとPHPで使用できます。
Jason Baker、

ただし、PHPで変数名を数字で始めることは許可されていません-言語規則では禁止されています。:-)しかし、同じ理由でQomposeを使用できます。
staticsan 09年

4

キーワードと識別子を数字で始めることを許可した場合、レクサー(コンパイラーの一部)は、数値リテラルの開始とキーワードを簡単に区別することができません。


2
字句解析プロセスがボトルネックになることはほとんどありません。もちろん、IDトークンの正規表現はより複雑になりますが、それでも超高速のDFAになる可能性があります。それらの実行時間は、コンパイラーが達成しなければならない他のほとんどのタスクと比較してピーナッツです。



2

言語設計者が規則を作ったので、C ++にはそれがありません。独自の言語を作成する場合、確かにそれを許可することができますが、おそらくそれらが行ったのと同じ問題に遭遇し、それを許可しないことにします。問題の原因となる変数名の例:

0x、2d、5555


この制限は、そのような構文が許可されていない言語にも当てはまります。
Jason Baker、

2

構文規則の緩和に関する主要な問題の1つは、コーディングプロセスに認知的不協和を導入することです。あなたのコードについてどう考えるかは、これがもたらす明快さの欠如に深く影響されます。

「ツールの最も重要な側面はユーザーへの影響である」と言ったのはDykstraでしたか?


1

おそらくそれが数字であるか識別子であるかを人間が識別しやすくするため、そして伝統のためです。数字で始まる可能性のある識別子があっても、字句スキャンはそれほど複雑にはなりません。

すべての言語が数字で始まる禁止された識別子を持っているわけではありません。Forthでは、それらは数値である可能性があり、小さな整数は通常、「2」を数値として認識するよりも、スタックに2をプッシュするルーチンとして「2」を読み取る方が速いため、Forthワード(基本的に識別子)として定義されていました。その値は2でした(プログラマーまたはディスクブロックからの入力を処理する際、Forthシステムはスペースに従って入力を分割します。定義された単語であるかどうかを確認するために辞書でトークンを検索しようとします。そうでない場合はそれを数値に変換しようとし、そうでない場合はエラーのフラグを立てます。


問題は、Forthには非常に高度なパーサーがないことです。実際、重要なのは、識別子が2組の空白の間にあるかどうかだけです。
Jason Baker、

1

シンボル名を数字で始めることを許可したとしましょう。ここで、変数12345foobarに名前を付けたいとします。これを12345とどのように区別しますか?正規表現を使用することは実際にはそれほど難しくありません。問題は実際にはパフォーマンスの1つです。なぜこれが非常に詳細であるのかは本当に説明できませんが、本質的には、12345foobarを12345と区別するにはバックトラックが必要であるという事実に帰着します。これにより、正規表現が非決定的になります。

これについては、こちらの説明がはるかに優れています


1
どのようにして、変数の命名許可するように正規表現を設計でしょうifqdoublezではなく、ifdouble?識別子が数字で始まることを許可することの基本的な問題は、完全に英数字で構成される既存の形式の16進リテラルと浮動小数点数があることです(言語は0x1234の代わりに$ 1234やh'1234のようなものを使用し、 1E23ピリオドを含めると、その問題を回避できます)。Cを正規表現解析しようとすると、のようなものによってすでにトリップする可能性があることに注意してください0x12E+5
スーパーキャット

1

コンパイラーは、数値ではなくメモリの場所でASCIIを使用して変数を簡単に識別できます。


1

コンパイラには次の7つのフェーズがあります。

  1. 字句解析
  2. 構文分析
  3. セマンティック分析
  4. 中間コード生成
  5. コードの最適化
  6. コード生成
  7. 記号表

コードの一部をコンパイルするときの字句解析フェーズでは、バックトラックが回避されます。Appleのような変数であるコンパイラーは、字句解析フェーズで文字「A」の文字に出会うとすぐにその識別子を認識します。ただし、123appleのような変数の場合、コンパイラーは「a」に到達するまで数値または識別子かどうかを判断できず、字句分析フェーズで変数であることを識別するためにバックトラックが必要になります。ただし、コンパイラではサポートされていません。

トークンを解析するときは、最初の文字を見て、それが識別子かリテラルかを判断し、それを正しい関数に送信して処理するだけで済みます。これがパフォーマンスの最適化です。


0

簡単な答えはそれができるということだと思います、制限は言語ベースです。C ++や他の多くの言語では、言語がサポートしていないため、それができません。それを許可するルールには組み込まれていません。

質問は、王がチェスで一度に4スペースを移動できないのはなぜかということと同じです。チェスでは違法な動きだからです。確かに別のゲームでそれはできますか?それは、プレイされているルールに依存します。


C ++がまだ生きている人々によって最近発明されたことを除いて。彼らがなぜ彼らがしたことを選び、代替案を拒否したのか彼らに尋ねることができます。同じことはチェスには適用されません。
スティーブジェソップ

しかし、それは私が主張していることではありません。これは、変数名の先頭に数字を入れられない理由についての類推であり、最も単純な答えは、言語の規則で許可されていないためです。
kemiller2002 2008

もちろんですが、質問者が愚か者だとは思いません。彼はおそらく自分ですでにそれまでに解決したでしょう。IMOの質問は、「言語のルールで許可されないのはなぜですか」です。彼はルールを知ることとルールを理解することのギャップを埋めたいと考えています。
スティーブジェソップ

ええ、これについて考えたとき、私はあなたがどこへ向かっているのかを理解しました。あなたはポイントを持っています。私はOccamのかみそりを少し自由に適用していたと思いますが、数値がないため、変数が数値で始まっていないことを除いて、理由に対する実際の答えはないと仮定しました。
kemiller2002 2008

私はあなたが間違っていると言っているのではありません、C ++標準化団体の決定が致命的な理解を超える場合があります。そして、あなたは「彼らは何かを決定しなければならなかったので、彼らはこれを決定したからです」。しかし、少なくとも尋ねられる質問があります:-)
Steve Jessop

0

もともとは、変数名を数字ではなく文字列として覚えやすい(より多くの意味を与えることができる)ためです。ただし、文字列内に数字を含めることで、文字列の意味を拡張したり、同じ変数名を使用したりできます。別個であるが密接な意味またはコンテキストを持つものとして指定されている。たとえば、loop1、loop2などは常に、ループに入っていること、および/またはループ2がloop1内のループであることを通知します。変数としてどちらを好みますか(より意味があります):アドレスまたは1121298?どちらが覚えやすいですか?ただし、言語がテキストや数値だけではないことを示すために何かを使用している場合($ addressの$など)、それは変数として扱われることをコンパイラーに指示するため、実際には違いはありません(この場合)。


0

変数は、コンパイラによってコンパイル時にも値と見なされるため、値は何度も再帰的に値を呼び出すことができます


0

コードの一部をコンパイルする際の字句解析フェーズでは、バックトラックは回避されます。Appleのような変数。、字句解析フェーズで文字「A」の文字に出会うと、コンパイラーはその識別子をすぐに認識します。ただし、123appleのような変数。、コンパイラーは、「a」に到達するまで数値または識別子であるかどうかを判断できず、字句解析フェーズで変数であることを識別するためにバックトラックが必要です。ただし、コンパイラではサポートされていません。

参照


0

変数の宣言に関しては、何も問題はありませんが、次のようにその変数を他の場所で使用しようとすると、あいまいさが生じます。

let 1 = "Hello world!" プリント(1)プリント(1)

printは、すべてのタイプの変数を受け入れるジェネリックメソッドです。そのため、その状況では、コンパイラーは(1)プログラマーが参照しているのがわかりません。整数値の1または文字列値を格納する1。この状況でコンパイラがそのようなものを定義できるようにする方が良いかもしれませんが、このあいまいなものを使用しようとするときは、修正機能を備えたエラーをそのエラーを修正してこのあいまいさを解消する方法に持って来てください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.