Почему почти во всех современных языках программирования (Go, Rust, Kotlin, Swift, Scala, Nim, даже последняя версия Python) типы всегда идут после имени переменной в объявлении переменной, а не раньше?
Почему x: int = 42
и нет int x = 42
?
Разве последнее не более читабельно, чем первое?
Это просто тенденция или есть какие-то действительно значимые причины этого решения?
programming-languages
language-design
syntax
Андре Поликанин
источник
источник
Ответы:
Все языки, о которых вы упомянули, поддерживают вывод типов , что означает, что тип является необязательной частью объявления в этих языках, потому что они достаточно умны, чтобы заполнить его сами, когда вы предоставляете выражение инициализации, которое имеет легко определяемый тип.
Это важно, потому что размещение необязательных частей выражения дальше вправо уменьшает неоднозначность при разборе и повышает согласованность между выражениями, которые используют эту часть, и теми, которые этого не делают. Проще разобрать объявление, когда вы знаете, что
var
ключевое слово и имя переменной являются обязательными, прежде чем вы перейдете к необязательному материалу. В теории, все те вещи , которые делают его более легким для синтаксического анализа для компьютеров должны улучшить общую читаемость для человека тоже, но это намного более спорно.Этот аргумент становится особенно сильным , когда вы учитываете все необязательные модификаторы типа , что «не современный» язык , как C ++ имеет, например,
*
для указателей,&
ссылок,const
,volatile
и так далее. Как только вы добавляете запятые для нескольких объявлений, вы начинаете получать некоторые действительно странные неясности, такие какint* a, b;
отсутствиеb
указателя.Даже C ++ теперь поддерживает объявления типа справа
auto x = int{ 4 };
, и у него есть некоторые преимущества .источник
var
которые обеспечивают большую часть упрощения синтаксического анализа.var
ключевого слова не противоречит цели обозначения «имя-имя»? Я не вижу преимущество написанияvar userInput: String = getUserInput()
надString userInput = getUserInput()
. Преимущество будет уместным только в том случае, еслиuserInput = getUserInput()
это также разрешено, но это подразумевает неявное объявление переменной области действия, что я нахожу довольно отвратительным.var userInput = getUserInput()
илиauto userInput = getUserInput()
, компилятор знает, чтоgetUserInput()
возвращает,String
поэтому вам не нужно указывать его с помощью ключевого слова deduction type.userInput = getUserInput()
конечно использовать перед объявлением.Ваша предпосылка ошибочна по двум направлениям:
Pascal, ML, CLU, Modula-2 и Miranda были очень влиятельными языками, поэтому неудивительно, что этот стиль объявлений типов оставался популярным.
Читаемость - это вопрос знакомства. Лично я считаю, что китайский нечитаем, но, видимо, китайцы этого не делают. Изучив Паскаль в школе, поболтав с Эйфелевой, F♯, Haskell и Scala, и посмотрев на TypeScript, Fortress, Go, Rust, Kotlin, Идрис, Фреге, Agda, ML, Ocaml,…, для меня это выглядит совершенно естественно ,
Если это тенденция, она довольно устойчивая: как я уже говорил, в математике она насчитывает сто лет.
Одним из основных преимуществ наличия типа после идентификатора является то, что он легко опускается, если вы хотите, чтобы он был выведен. Если ваши объявления выглядят так:
Тогда тривиально опустить тип и вывести его следующим образом:
Принимая во внимание, что если тип предшествует идентификатору, как это:
Затем парсеру становится трудно отличить выражение от объявления:
Решение, которое обычно предлагают разработчики языка, состоит в том, чтобы ввести ключевое слово «Я не хочу писать тип», которое должно быть написано вместо типа:
Но на самом деле это не имеет особого смысла: вы должны явно написать тип, который говорит, что вы не пишете тип. А? Было бы намного проще и разумнее просто оставить это, но это делает грамматику намного более сложной.
(И давайте даже не будем говорить о типах указателей на функции в C.)
Разработчики нескольких из вышеупомянутых языков взвесили эту тему:
Go FAQ (см. Также: Синтаксис декларации Go ):
Kotlin FAQ :
Программирование в Scala :
Примечание: разработчики Ceylon также задокументировали, почему они используют синтаксис префиксного типа :
Лично я нахожу их «аргумент» гораздо менее убедительным, чем другие.
источник
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.Кстати, Паскаль делает это тоже, и это не новый язык. Это был академический язык, разработанный с нуля.
Я бы сказал, что семантически понятнее начинать с имени переменной. Тип это просто техническая деталь. Если вы хотите читать свой класс как модель реальности, то имеет смысл вначале указывать имена ваших сущностей, а в конце - их техническую реализацию.
C # и Java происходят от C, поэтому они должны уважать «уровень техники», чтобы не перепутать опытного программиста.
источник
В таком простом примере нет особой разницы, но давайте сделаем его немного сложнее:
int* a, b;
Это действительное, правильное объявление в C, но оно не делает то, что выглядит интуитивно, как должно. Похоже, мы объявляем две переменные типа
int*
, но на самом деле мы объявляем однуint*
и однуint
.Если ваш язык помещает тип после имени (имен) переменных в своих объявлениях, с этой проблемой невозможно столкнуться.
источник
x, y *int;
два*int
или один*int
и одинint
? Созданиеint*
или*int
один токен вместо двух может решить эту проблему, или использование дополнительного синтаксического элемента, такого как:
, который может работать в любом направлении.:
илиas
, между именем и типом.x, y int
без разделителя.x, y *int
означает «объявить две переменные, x и y, с указателем типа на int».int[] x, y
как два массива. Это просто глупый синтаксис C, который рассматривает эти модификаторы как унарные операторы в переменной (и не менее, как префикс и постфикс), что вызывает проблемы.