Syntactic Sugar のWikipediaページには、次のように記載されています。
コンピュータサイエンスでは、シンタックスシュガーは、物事を読みやすくしたり表現したりできるように設計されたプログラミング言語内の構文です。人間が使用する言語を「より甘い」にします。物事をより明確に、より簡潔に、または一部の人が好む代替スタイルで表現できます。
構文糖と構文の違いがよくわかりません。
甘いバージョンがより明確で簡潔になる可能性があるという点に感謝します。しかし、私はあるレベルで感じます。すべての構文は、コードがコンパイルされる対象を抽象化するために基本的にそれを行っています。
同じWikipediaページから:
コンパイラー、静的アナライザーなどを含む言語プロセッサーは、処理の前に糖化構造をより基本的な構造に展開することがよくあります。このプロセスは、「脱糖化」と呼ばれることもあります。
思考の練習として、このステートメントで「常に」を「頻繁に」取る場合:コンパイラが次の段階に進む前に構文を「デガー」するかどうかだけの違いである場合、内部を知らないコーダーはどうすればよいでしょうか。コンパイラーは、Sugar'd Syntaxとは何かを知っています(または気にします)。
このサイトの非常に関連する質問 "構文上の砂糖の厳密な定義?" には answer があり、次のように始まります:
私見私はあなたが構文糖の定義を持つことができないと思います、なぜならフレーズはBSであり、「実際のオペレーティングシステム」で「実際のツール」を使って「実際のプログラマー」について話す人々によって使われる可能性が高いからです
言語を使用するコーダーに大きな違いはないのではないでしょうか?おそらく、違いはコンパイラの作成者にしか認識されませんか?シンタクティックシュガーの内部に何があるかを知ることが、言語を使用するコーダーにとって役立つ場合があるかもしれませんが? (しかし、実際には、主題に関する任意の談話は、この用語を炎の餌として使用する傾向がありますか?)
だから...質問の短いバージョン:
トピックの矛盾に関するボーナス:
ウィキペディアのページに例が示されています:
たとえば、C言語では_
a[i]
_表記は*(a + i)
の構文糖衣です
一方、上記のリンクされた質問の別の answer は、同じ例について述べています。
次に、
a[i] == *(a + i)
について考えます。配列を実質的な方法で使用するCプログラムについて考えてみてください。
そしてそれを要約します:
_
[]
_表記は、この抽象化を容易にします。それは構文上の砂糖ではありません。
同じ例の反対の結論!
主な違いは、構文は言語で定義された文法であるため、一部の機能を公開できることです。その機能に到達するとすぐに、同じことを実行できるother構文は砂糖と見なされます。もちろん、特にどちらが最初に来たのかが必ずしも明確ではないため、2つの構文のどちらが砂糖であるかについての奇妙なシナリオに遭遇します。
実際には、構文シュガーは、インフィックス_lhs + rhs
_をlhs.Add(rhs)
にマップするなど、使いやすさを促進するために言語に追加された構文を記述するためにのみ使用されます。私はCの配列のインデックス付けを構文上の砂糖だと考えています。
エレガントなデザインは複製の量を制限する傾向があるため、これは主に重要です。構文糖を必要とする(または少なくとも必要とする)ことは、設計が失敗したことを示すものと見なされています。
構文は、言語プロセッサが言語の構造の意味を理解するために使用するものです。構文糖と見なされる構成要素も、言語プロセッサによって解釈される必要があるため、言語構文の一部です。
言語の構文の残りの部分とは別に構文シュガーを設定するのは、言語で記述できるプログラムに影響を与えることなく、言語から構文シュガーを削除できるということです。
より形式的な定義を与えるために、私は言うでしょう
構文シュガーは、言語の構文の一部であり、その効果は、その言語の他の構文構成要素によって定義されます。
構文糖質を使用すると、プログラムの意図が理解しやすくなることが多いため、これは構文糖質またはそれを含む言語を害することを意味するものではありません。
他の回答では、主要な概念について言及していません。抽象的な構文;これがないと、「構文糖」という用語は意味がありません。
抽象構文は、言語の要素と構造、およびその言語のフレーズを組み合わせてより大きなフレーズを作成する方法を定義します。抽象構文は、具体的な構文から独立しています。 「構文糖」という用語は、私が理解しているように、具体的な構文を指します。
一般に、言語を設計するときは、抽象構文の各用語に対して具体的な構文を作成して、人々がプレーンテキストを使用して言語でコードを記述できるようにする必要があります。
fooのぎこちない具体的な構文を作成するとします。ユーザーは不平を言い、あなたは同じ抽象構文を表す新しい具象構文を実装します。その結果、抽象的な構文とセマンティクスは変更されていませんが、同じ抽象構文の用語に対して2つの具体的な構文があります。
これは、人々が「構文糖」と言うときの意味です。具体的な構文にのみ影響を与えるが、抽象的な構文やセマンティクスには影響を与えない変更です。
そして、「構文糖」と「具体的な構文」の違いが明確になりました。私に。 :)
この解釈は、アランペルリスが「構文糖がセミコロンの癌を引き起こす」と言ったときに何を意味していたかを説明するのにも役立ちます。世界中のすべての具体的な構文糖は、弱い抽象構文を修正できません。実際の問題、つまり抽象的な構文の処理に費やしていない労力。
また、これは私の意見にすぎません。それは私が理解できる唯一の解釈だと思うので、私はそれを信じています。
構文糖衣は、言語構文のサブセットです。基本的な考え方は、同じことを言うには複数の方法があるということです。
構成要素difficultどの部分が構文糖であり、どの部分が「純粋な構文」であるかを示すのは、「どの形式が最初に来たのかを言うのは難しい」または「作者がどちらの方法であるかを知るのが難しい」などのステートメントです。 「意図された言語」または「どちらの形式がより単純であるかを決定するのはいくぶん恣意的」です。
何がeasyなのかを決定するのは、特定のコンパイラまたはインタープリタの枠内で質問することです。純粋な構文とは、コンパイラが直接マシンコードに変換するもの、またはインタプリタが直接応答するものです。砂糖は、これらの直接的なことが起こる前に、最初に他の構文に変換されるものです。実装に応じて、これは作者が意図したもの、または言語仕様が主張するものと同じである場合も、そうでない場合もあります。
実際には、これは問題の現実が決定される方法です。
通常、シンタックスシュガーは、一般性を失うことなく言語の既存の部分(構文)で表現できる言語の一部ですが、明確性を失う可能性があります。コンパイラーには、ソースコードによって作成されたASTを変換し、砂糖に対応するノードを削除するための簡単なステップを適用する明示的な脱糖ステップがあります。
たとえば、Haskellには次のルールが再帰的に適用されるモナドの構文糖があります
do { f } ~> f
do { g; h } ~> g >> do h
do { x <- f; h } ~> f >>= \x -> do h
do { let x = f; h } ~> let x = f in do h
今のところ、それが何を意味するかは問題ではありません。ただし、LHSの特別な構文は、RHSのより基本的なもの(つまり、関数アプリケーション、ラムダ、let
's)に変換できることがわかります。この手順により、両方の長所を維持できます。
同様に、Cでは、書き換えルールのデシュガリングを想像できます(演算子のオーバーロードなどにより、C++には当てはまりません)。
f->h ~> (*f).h
f[h] ~> *(f + h)
今日、この構造を使用するCで->
または[]
を使用せずにすべてのプログラムを書くことを想像できます。しかし、プログラマーがそれを使用するのはより難しく、したがって、構文糖が提供されます(70年代には、コンパイラーの作業も簡略化したと思います)。次の完全に有効な書き換えルールを技術的に追加できるため、不明確になる可能性があります。
*f ~> f[0] -- * and [] have the same expressiveness
構文糖は悪いですか?必ずしもそうではありません-より深い意味を理解せずに貨物カルトとして使用される危険があります。たとえば、次の関数はHaskellで同等ですが、多くの初心者は構文糖衣を多用していることを理解せずに最初のフォームを記述します。
f1 = do x <- doSomething
return x
f2 = doSomething
さらに、構文シュガーは言語を複雑にしすぎたり、狭すぎて一般化された慣用コードを使用できない場合があります。また、言語は特定のことを簡単に実行するのに十分強力ではないことを意味するかもしれません-それは設計によるかもしれません(開発者に鋭いツールや非常に特定のニッチ言語を与えないでください、より強力な構成を追加すると他の目標を損なうでしょう)省略によって-後者フォームは構文糖に悪い名前を与えました。言語が構文糖を追加せずに他の構成を使用するのに十分強力な場合、それらを使用する方がよりエレガントであると考えられます。
最もわかりやすい例は、Cの「+ =」構文でしょう。
i = i + 1;
そして
i += 1;
まったく同じことを行い、まったく同じ機械語命令のセットにコンパイルします。 2番目のフォームでは、入力する2、3文字を節約できますが、より重要なのは、現在の値に基づいて値を変更していることを非常に明確にします。
私は "++"のpost/prefix演算子を標準的な例として引用しようとしましたが、これは構文上の砂糖以上のものであることに気付きました。 i = i + 1
構文を使用して、++ iとi ++の違いを単一の式で表す方法はありません。
本当に、Wikipediaからの最初の引用は、「...物を読みやすくする...」、「...人間にとって使いやすい...」とすべて述べています。
書面では、「しない」または「持っていない」などの短縮形は、構文上の砂糖と見なすことができます。
フレーズの元々の意味が何であれ、今日では主に軽蔑的な表現であり、ほとんど常に「ただ」または「唯一」の構文糖と表現されています。それは、判読できない方法で物事を行い、それを同僚に正当化する簡潔な方法を望んでいるプログラマーにとって、ほとんど重要です。今日主にこの用語を使用している人々の定義は、彼らの観点からすると、次のようになります。
言語をあまり理解していないプログラマーに松葉杖を提供するために、他のより広く適用可能な構文と冗長な構文。
そのため、同じ構文要素に対して2つの反対の結論が得られます。配列表記の最初の例は、用語の元の肯定的な意味を使用しています。これは、バートの回答に似ています。 2番目の例は、苛立たしい意味での構文糖であるという罪から配列表記を守ることです。つまり、構文は松葉杖ではなく、有用な抽象概念であると主張しています。
最初に、他の回答のいくつかを具体例を使って説明します。 C++ 11の範囲ベースのforループ(他のさまざまな言語のforeachループとよく似ています)
_for (auto value : container) {
do_something_with(value);
}
_
と完全に同等です(つまり、の砂糖漬けバージョン)
_for (auto iterator = begin(container); iterator != end(container); ++iterator) {
do_something_with(*iterator);
}
_
現在、新しい抽象構文やセマンティクスを言語に追加していませんが、実際の実用性があります。
最初のバージョンでは、意図(コンテナ内のすべてのアイテムにアクセス)を明示的にしています。また、トラバーサル中にコンテナーを変更したり、ループ本体でiterator
をさらに進めたり、ループ条件を微妙に間違ったりするなどの異常な動作も禁止します。これにより、バグの発生源となる可能性を回避し、コードの読み取りと推論の難しさを軽減します。
たとえば、2番目のバージョンでの1文字の間違い:
_for (auto iterator = begin(container); iterator <= end(container); ++iterator) {
do_something_with(*iterator);
}
_
過去の終わりのエラーと未定義の動作を与えます。
したがって、シュガー付きバージョンは、制限が厳しく、信頼して理解することがより簡単になるため、正確に役立ちます。
第二に、元の質問に:
シンタックスシュガーとシンタックスシュガーの間に本当の違いはありますか?
いいえ、「構文糖」は(具体的な)言語構文であり、言語の抽象的な構文やコア機能を拡張しないため、「糖」と見なされます。私はこれについてのマット・フェンウィックの答えが好きです。
それは誰にとって重要ですか?
他の構文と同様に、言語のユーザーにとって重要であり、その砂糖は特定のイディオムをサポートする(そしてある意味では祝福する)ために提供されます。
最後に、ボーナスの質問について
[]表記は、この抽象化を容易にします。
これは、構文糖質のdefinitionによく似ています。これは、ポインタを配列として使用することをサポートします(そして言語の作者の祝福を提供します)。 _p[i]
_フォームは*(p+i)
ほど制限が少ないため、唯一の違いは、意図の明確な伝達(およびわずかな読みやすさの向上)です。