Чому тип має назву змінної у сучасних мовах програмування?


57

Чому так, що майже в усіх сучасних мовах програмування (Go, Rust, Kotlin, Swift, Scala, Nim, навіть остання версія Python) типи завжди приходять після імені змінної в декларації змінної, а не раніше?

Чому x: int = 42і ні int x = 42?
Чи останні не є більш читабельними, ніж перші?
Це просто тенденція чи є якісь справді значущі причини, що стоять за цим рішенням?



3
Так, це добре. Хоча це стосується конкретно мови Котліна, питання (та його відповіді) стосується всіх мов, що мають цю практику.
Роберт Харві


2
Вибачте, хлопці, я бачив питання про Котліна під час гуглінгу, але я повторно попросив його не отримувати відповіді на кшталт "Тому що Котлін (Іди, Іржа, ...) команда розробників вирішила так". Мене зацікавила більш поширена відповідь: чому це стає своєрідною епідемією?
Андре Поліканін

2
Хіхі, тож Delphi, що є (Object) Pascal, і мав типи після змінних імен з моменту свого створення, назад, коли в темні століття минулого століття знову сучасний;) Btw, читабельність сильно впливає на те, що ти є звик. Починаючи з Delphi, C # та його тип до назви вару змусили мене стукати головою досить довго.
Мар'ян Венема

Відповіді:


64

Усі мови, про які ви згадали, є висновками про тип підтримки , а це означає, що тип є необов'язковою частиною декларації на цих мовах, оскільки вони досить розумні, щоб заповнити їх у себе, коли ви надаєте вираз ініціалізації, який має легко визначити тип.

Це важливо, оскільки розміщення необов'язкових частин виразу далі праворуч зменшує розбір неоднозначності та збільшує узгодженість між виразами, які використовують цю частину, та тими, які не використовують. Простіше проаналізувати декларацію, коли ви знаєте, що varключове слово та ім’я змінної обоє є обов'язковими, перш ніж перейти до необов'язкового матеріалу. Теоретично, все те, що полегшує розбір для комп’ютерів, також повинно покращити загальну читанність для людей, але це набагато більш дискусійно.

Цей аргумент стає особливо сильним , коли ви враховуєте всі необов'язкові модифікатори типу , що не «сучасний» мову , як C ++ має, наприклад, *для покажчиків, &для посилань const, volatileі так далі. Як тільки ви кидаєте коми для декількох декларацій, ви починаєте отримувати деякі дійсно дивні неоднозначності, як int* a, b;не робити bпокажчик.

Навіть C ++ тепер підтримує декларації типу "праворуч" у формі auto x = int{ 4 };, і це має деякі переваги .


2
+1 за визнання існування таких обов'язкових ключових слів, varякі забезпечують більшість спрощення розбору.
8bittree

2
Чи не існування varключового слова перешкоджає призначенню першої імені? Я не бачу перевагу написання var userInput: String = getUserInput()над String userInput = getUserInput(). Перевага буде доречною лише тоді, коли userInput = getUserInput()це також дозволено, але це означатиме неявне декларування масштабної змінної, яке я вважаю досить невірним.
kdb

2
@kdb на таких мовах, як C # і C ++, це було б, var userInput = getUserInput()або auto userInput = getUserInput()компілятор знає getUserInput()повернення, Stringтому вам не потрібно вказувати це за допомогою ключового слова відрахування типу. userInput = getUserInput()звичайно використовувати перед декларуванням.
Уес Толеман

32

Чому майже у всіх сучасних мовах програмування (Go, Rust, Kotlin, Swift, Scala, Nim, навіть остання версія Python) типи завжди надходять після оголошення змінної, а не раніше?

Ваше приміщення є недоліком на двох фронтах:

  • Існують нові мови програмування, які мають тип перед ідентифікатором. Наприклад, C♯, D або Цейлон.
  • Наявність типу після ідентифікатора не є новим явищем, воно повертається принаймні до Паскаля (розроблений 1968-1969 рр., Випущений у 1970 р.), Але насправді використовувався в математичній теорії типів, яка починається з 1902 р. Він також використовувався в ML (1973), CLU (1974), Hope (1970), Modula-2 (1977–1985), Ada (1980), Міранда (1985), Caml (1985), Eiffel (1985), Oberon (1986), Модула-3 (1986–1988) та Хаскелл (1989).

Паскаль, ML, CLU, Modula-2 і Miranda всі були дуже впливовими мовами, тому не дивно, що цей стиль декларацій типу залишався популярним.

Чому x: int = 42і ні int x = 42? Чи останні не є більш читабельними, ніж перші?

Читання - це питання знайомства. Особисто я вважаю китайську мову нечитаючою, але, мабуть, китайці цього не роблять. Дізнавшись Паскаля в школі, посварившись з Ейфелем, F♯, Хаскеллом та Скалою, а також подивившись на TypeScript, Fortress, Go, Rust, Kotlin, Idris, Frege, Agda, ML, Ocaml,…, мені це здається абсолютно природним .

Це просто тенденція чи є якісь справді значущі причини, що стоять за таким рішенням?

Якщо це тенденція, вона досить наполеглива: як я вже згадував, це математика йде на сто років назад.

Однією з головних переваг наявності типу після ідентифікатора є те, що легко залишити тип, якщо ви хочете, щоб він міг зробити висновок. Якщо ваші декларації виглядають так:

val i: Int = 10

Тоді тривіально виключати тип і робити це таким чином:

val i = 10

Беручи до уваги, якщо тип стоїть перед таким ідентифікатором:

Int i = 10

Тоді аналізатору починає важко відрізняти вираз від декларації:

i = 10

Рішення, яке зазвичай розробляють мовні дизайнери, - це ввести ключове слово "Я не хочу писати тип", яке потрібно писати замість типу:

var  i = 10; // C♯
auto i = 10; // C++

Але це насправді не має великого сенсу: в основному ви повинні явно написати тип, який говорить про те, що ви не пишете тип. Так? Було б набагато простіше і розумніше просто залишити це, але це робить граматику набагато складнішою.

(І давайте навіть не говорити про типи вказівників функцій у C.)

Дизайнери кількох вищезгаданих мов зважили на цю тему:

  • Перейти до поширених запитань (див. Також: Синтаксис декларації Go ):

    Чому декларації зворотні?

    Вони лише назад, якщо ви звикли до C. У C поняття полягає в тому, що змінна оголошується як вираз, що позначає її тип, що є приємною ідеєю, але граматики типу та виразів не дуже добре поєднуються, і результати можуть бути заплутаними; розглянемо функціональні покажчики. Переважно розділяє синтаксис виразів і типів, що спрощує речі (використання префікса *для покажчиків - виняток, що підтверджує правило). В С декларація

    int* a, b;
    

    оголошує aвказівником, але ні b; в Го

    var a, b *int
    

    оголошує обох покажчиками. Це чіткіше і регулярніше. Також :=форма короткої декларації стверджує, що повна заява змінної повинна представляти той самий порядок, що і :=так

    var a uint64 = 1
    

    має такий же ефект, як і

    a := uint64(1)
    

    Парсинг також спрощується, маючи чітку граматику для типів, які не є лише граматикою виразу; такі ключові слова, як funcі chanзабезпечують чіткість.

  • Котлін FAQ :

    Чому праворуч декларації типу?

    Ми вважаємо, що це робить код читабельнішим. Крім того, це дає деякі приємні синтаксичні особливості. Наприклад, легко залишити анотації типу. Scala також досить добре зарекомендувала себе, це не проблема.

  • Програмування в Scala :

    Основне відхилення від Java стосується синтаксису для анотацій типів - це " variable: Type" замість " Type variable" у Java. Синтаксис типу постфікса Scala нагадує Паскаль, Модулу-2 або Ейфель. Основна причина цього відхилення пов'язана з висновком типу, який часто дозволяє опускати тип змінної або тип повернення методу. Використовувати variable: Typeсинтаксис " " це легко - просто залиште двокрапку та тип. Але в Type variableсинтаксисі стилю C " " ви не можете просто залишити тип - маркер, який би починав визначення, більше не мав би. Вам знадобиться якесь альтернативне ключове слово, щоб бути заповнювачем для відсутнього типу (C♯ 3.0, який робить певний тип виводу, використовується varдля цієї мети). Таке альтернативне ключове слово вважається більш спеціальним та менш регулярним, ніж підхід Scala.

Примітка: дизайнери Цейлону також задокументували, чому вони використовують синтаксис типу префікса :

Префікс замість анотацій типу постфікса

Чому ви дотримуєтесь C та Java, коли в першу чергу викладаєте анотації типу, а не Pascal та ML, а їх після імені декларації?

Тому що ми думаємо так:

shared Float e = ....
shared Float log(Float b, Float x) { ... }

Просто читати набагато простіше, ніж це:

shared value e: Float = .... 
shared function log(b: Float, x: Float): Float { ... }

І ми просто не розуміємо, як хтось може подумати інакше!

Особисто я вважаю їх "аргумент" набагато менш переконливим, ніж інші.


4
Здається , здатність вийти з типу і до сих пір просто синтаксичний надаються шляхом додавання var, auto, letчи щось таке, а НЕ на якого боку змінної декларація типу включена. var Int x = 5або навіть їх Int var x = 5можна було б скоротити до var x = 5.
8bittree

5
Хоча я люблю це однаково читабельно, коли ви звикаєте до нього і необов'язковий аргумент типу є сильним, я хотів би зазначити, що IDE не в змозі автоматично запропонувати імена змінних на основі типу. Я сумую за цим, коли пишу TypeScript.
П’єр Генрі

"Your premise is flawed on two fronts" Усі вони новіші за C # або D.
Дет

3
"Але це насправді не має великого сенсу: ви в основному повинні чітко написати тип, який говорить про те, що ви не пишете тип." Що ж, версія типу праворуч точно така ж у вашому прикладі ... Також я не згоден, що це не має сенсу. Це має стільки ж сенсу, як funcу Go.
Сопель

4

Паскаль робить це теж до речі, і це не нова мова. Це була академічна мова, але розроблена з нуля.

Я б сказав, що семантично зрозуміліше починати з назви змінної. Тип - це лише технічна деталь. Якщо ви хочете прочитати свій клас на зразок такої моделі реальності, має сенс спочатку поставити назви ваших організацій та їх технічну реалізацію.

C # і java походять від C, тому їм довелося поважати "попередній рівень техніки", щоб не плутати досвідченого програміста.


3
Ада також робить це так, але, безумовно, Ада не є "академічною мовою".
Джон Р. Стром

Ада зробила це тому, що сильно пограла з Паскаля та Модули 2.
Gort the Robot

2
Швидкий пошук @StevenBurnap виявляє, що перша книга Вірта про Модулу-2 вийшла в середині 1982 року. Ада була в стадії розробки кілька років до цього (DoD1 був у 1977 році, або, як я пам’ятаю), і був стандартизований, як стандарт ANSI, так і MIL-STD, у 1983 році. Усі чотири команди, які подали кандидатів на Ada, взяли PASCAL як їх вихідні точки. (Doll Labs запросив DoD подати мову кандидата на основі C. Вони демунізували, сказавши, що C тоді не був і ніколи не буде достатньо надійним для критичного програмного забезпечення DoD.)
John R. Strohm

Я, мабуть, неправильно пам'ятаю. Я думав, Вірт був причетний до Ада.
Гурт Робота

Паскаль розпочав академічну мову, але до кінця 90-х він був на межі того, що мовою писати програми для Windows через Delphi, тобто до того часу, поки Борланд не стрибнув акулу з цінами і не залишив двері відкритими для Java та C # для приходь і вкраде приз. Ви все ще побачите тонну Delphi там, у застарілому світі додатків Windows.
Шейне

1

Чому x: int = 42і ні int x = 42? Чи останні не є більш читабельними, ніж перші?

У такому простому прикладі різниці немає, але давайте зробимо це трохи складніше: int* a, b;

Це дійсна, дійсна декларація в C, але вона не робить те, що інтуїтивно виглядає так, як це повинно робити. Схоже, ми оголошуємо дві змінні типу int*, але насправді ми оголошуємо одну int*та одну int.

Якщо ваша мова в своїх деклараціях вводить тип після імені змінної, цієї проблеми неможливо зіткнутися.


4
Я не впевнений, чому переміщення декларації типу після вплине на це. Є x, y *int;два *intабо один *intі один int? Створення int*або *intодного маркера замість двох вирішило б це, або використовуючи додатковий синтаксичний елемент на зразок :, який може працювати в будь-якому напрямку.
8bittree

@ 8bittree Кожна мова, з якою я знайома, що використовує декларації з першими іменами, використовує додатковий маркер, як-от :або as, між назвою та типом.
Мейсон Вілер


2
А в Go x, y *intозначає «оголосити дві змінні, x і y, з типом вказівника на int».
Ватін

10
C # використовує синтаксис префікса, проте він розглядає int[] x, yяк два масиви. Це просто нерозумний синтаксис С, який розглядає ці модифікатори як одинарні оператори змінної (і суміш префікса та постфікса, не менше), що викликає проблеми.
CodesInChaos
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.