Из языкового руководства Java 5 :
Когда вы видите двоеточие (:) читайте его как «в».
Почему бы не использовать in
в первую очередь тогда?
Это беспокоило меня годами. Потому что это несовместимо с остальной частью языка. Например, в Java есть implements
, extends
, super
для отношений между типами вместо символов , как в C ++, Scala или Ruby.
В Java двоеточие используется в 5 контекстах . Три из которых унаследованы от C. А два других были одобрены Джошуа Блохом. По крайней мере, так он говорил во время разговора «Споры о замыканиях» . Это возникает, когда он критикует использование двоеточия для отображения как несовместимое с семантикой for-each. Что мне кажется странным, потому что это ожидаемое поведение для каждого злоупотребленного. Нравится list_name/category: elements
или laberl/term: meaning
.
Я слонялся вокруг jcp и jsr, но не нашел никаких признаков списка рассылки. Google не нашел никаких обсуждений по этому вопросу. Только новички путают смысл двоеточия в России for
.
Основные аргументы против in
предоставленного до сих пор:
- требует нового ключевого слова; а также
- усложняет лексизм.
Давайте посмотрим на соответствующие определения грамматики :
заявление : оператор for ('forControl') ' | ... ; для управления : extendedForControl | ForInit? ';' выражение? ';' ForUpdate? ; enhancedForControl : variableModifier * тип variableDeclaratorId ':' выражение ;
Измените, :
чтобы in
не принести дополнительную сложность или требует нового ключевого слова.
Ответы:
Нормальные парсеры, как их обычно учат, имеют стадию лексера, прежде чем парсер коснется ввода. Лексер (также «сканер» или «токенизатор») разбивает входные данные на маленькие токены, помеченные типом. Это позволяет основному синтаксическому анализатору использовать токены в качестве терминальных элементов, а не обрабатывать каждый символ как терминальный, что приводит к заметному повышению эффективности. В частности, лексер также может удалить все комментарии и пробелы. Тем не менее, отдельная фаза токенизатора означает, что ключевые слова также не могут использоваться в качестве идентификаторов (если язык не поддерживает удаление, которое несколько утратило популярность, или префикс всех идентификаторов с символом, подобным символу
$foo
).Почему? Предположим, у нас есть простой токенизатор, который понимает следующие токены:
Токенайзер всегда будет соответствовать самому длинному токену и предпочитать ключевые слова идентификаторам. Так
interesting
будет лексировано какIDENT:interesting
, ноin
будет лексировано какIN
никогдаIDENT:interesting
. Фрагмент кода какбудет переведен в поток токенов
Пока что это работает. Но любая переменная
in
будет указана как ключевое слово,IN
а не как переменная, что нарушит код. Лексер не хранит никакого состояния между токенами и не может знать, что этоin
обычно должна быть переменная, кроме случаев, когда мы находимся в цикле for. Также следующий код должен быть законным:Первый
in
будет идентификатором, второй будет ключевым словом.Есть две реакции на эту проблему:
Контекстные ключевые слова сбивают с толку, давайте вместо этого будем использовать ключевые слова.
В Java много зарезервированных слов, некоторые из которых бесполезны, за исключением предоставления более полезных сообщений об ошибках программистам, переходящим на Java с C ++. Добавление новых ключевых слов нарушает код. Добавление контекстных ключевых слов вводит читателя в заблуждение, если у них нет хорошей подсветки синтаксиса, и затрудняет реализацию инструментов, поскольку им придется использовать более продвинутые методы синтаксического анализа (см. Ниже).
Когда мы хотим расширить язык, единственным разумным подходом является использование символов, которые ранее были недопустимы в языке. В частности, это не могут быть идентификаторы. С помощью синтаксиса цикла foreach Java повторно использовала существующее
:
ключевое слово с новым значением. С лямбдами Java добавила->
ключевое слово, которое ранее не могло встречаться ни в одной легальной программе (-->
все равно будет помечено как'--' '>'
допустимое и->
ранее могло быть помечено как'-', '>'
, но эта последовательность будет отклонена синтаксическим анализатором).Контекстные ключевые слова упрощают языки, давайте их реализовывать
Лексические бесспорно полезны. Но вместо того, чтобы запускать лексер перед парсером, мы можем запускать их вместе с парсером. Восходящие синтаксические анализаторы всегда знают набор типов токенов, которые были бы приемлемы в любом заданном месте. Затем парсер может запросить лексер для сопоставления с любым из этих типов в текущей позиции. В цикле for-each парсер будет в позиции, обозначенной
·
в (упрощенной) грамматике после того, как переменная найдена:На этой позиции легальными токенами являются
SEMICOLON
илиIN
, но нетIDENT
. Ключевое словоin
было бы совершенно однозначным.В этом конкретном примере парсеры сверху вниз также не будут иметь проблем, поскольку мы можем переписать приведенную выше грамматику в
и все жетоны, необходимые для решения, можно увидеть без возврата.
Учитывайте удобство использования
Ява всегда была склонна к семантической и синтаксической простоте. Например, язык не поддерживает перегрузку операторов, потому что это сделает код намного более сложным. Таким образом, при выборе между
in
и:
для синтаксиса цикла for-each, мы должны учитывать, что является менее запутанным и более очевидным для пользователей. Крайний случай, вероятно, будет(Примечание: Java имеет отдельные пространства имен для имен типов, переменных и методов. Я думаю, что это, в основном, ошибка. Это не означает, что в более поздних версиях языка придется добавлять больше ошибок.)
Какая альтернатива обеспечивает более четкое визуальное разделение между переменной итерации и повторяющейся коллекцией? Какую альтернативу можно распознать быстрее, если взглянуть на код? Я обнаружил, что разделяющие символы лучше, чем цепочка слов, когда дело доходит до этих критериев. Другие языки имеют разные значения. Например, Python расшифровывает множество операторов на английском языке, чтобы их можно было читать естественным образом и легко понять, но эти же свойства могут затруднить понимание части Python с первого взгляда.
источник
Синтаксис цикла for-each был добавлен в Java 5. Вам нужно было бы создать
in
ключевое слово языка, а добавление ключевых слов в язык - это то, чего вы избегаете любой ценой, потому что это нарушает существующий код - внезапно все именованные переменныеin
вызывают синтаксический анализ ошибка.enum
было достаточно плохо в этом отношении.источник
in
означало бы либо ввести новое ключевое слово, нарушив тем самым обратную совместимость (System.in
кто-нибудь?), Либо ввести ранее неизвестную совершенно новую концепцию (контекстные ключевые слова). Все ради чего?for(variable in expression)
никогда не может быть неоднозначным с любым юридическим кодом, даже если «in» может использоваться для переменных. Однако отдельная фаза лексера довольно распространена во многих цепочках компиляторов. Это сделало бы невозможным или, по крайней мере, намного более сложным для анализа Java с некоторыми распространенными генераторами синтаксического анализатора. Простота синтаксиса языка обычно полезна для всех участников; не всем нужны синтаксические чудовища, такие как C ++ или Perl.const
иgoto
оба являются зарезервированными словами в Java, но не используются (пока).