Поступове введення тексту: "Майже кожна мова зі системою статичного типу також має систему динамічного типу"


20

Ця вимога по Aleks Бромфілд говорить:

Практично кожна мова зі системою статичного типу також має систему динамічного типу. Крім C, я не можу придумати винятку

Це поважна претензія? Я розумію, що за допомогою рефлексії або завантаження класів під час виконання Java стає дещо подібним - але чи може ця ідея "поступового набору тексту" поширюватися на велику кількість мов?


Я не мовний експерт, але декілька, які миттєво приходять до тями, що я не вірю, що у них є динамічні типи (Рідно, не кажучи, що ти не зміг би щось спільно в них) - Fortran, Ada, Pascal, Cobol
mattnz

4
Я мовний експерт, і я не впевнений, на що претендує цей хлопець. "статичний" і "динамічний" є неправильними і зазвичай вказують час перевірки / аналізу типу (чи під час компіляції, або під час виконання). Деякі мови узгоджують обидві (наприклад, забороняючи операції над непідтримуваними типами під час компіляції та збільшення винятків, таких як ClassCastException під час виконання), і це може бути саме він. Якщо так, то це правда, що C зазвичай не виконує перевірку типу під час виконання. Говорячи ланг. не має "системи динамічного типу" не має сенсу.
Тіаго Сільва

Відповіді:


37

Оригінальний твіттер тут. :)

По-перше, я трохи розвеселений / шокований, що мій твіт так сприймається серйозно! Якби я знав, що це буде широко розповсюджений, я витратив би більше 30 секунд на його написання!

Тіаго Сільва правильно зазначає, що "статичні" та "динамічні" точніше описують перевірку типу , а не системи типів . Насправді сказати, що мова є статично чи динамічно введеною, не дуже точно. Швидше, мова має систему типів, і реалізація цієї мови може примусити систему типів використовувати статичну перевірку, або динамічну перевірку, або те і інше, або жодне (хоча це не буде дуже привабливою мовною реалізацією!).

Як це буває, існують певні типові системи (або особливості систем типів), які піддаються статичній перевірці, і є певні системи типів (або особливості систем типів), які більше піддаються динамічній перевірці. Наприклад, якщо ваша мова дозволяє вказувати в тексті програми, що певне значення завжди повинно бути масивом цілих чисел, тоді досить просто написати статичну перевірку для перевірки цього властивості. І навпаки, якщо у вашій мові є підтипи, і якщо це дозволяє скидання каналу, то перевірити обґрунтованість перерви вниз під час виконання досить просто, але це надзвичайно важко зробити під час компіляції.

Що я дійсно мав на увазі під своїм твіттом, це просто те, що переважна більшість мовних реалізацій виконують деяку кількість динамічної перевірки типу. Або, що рівно, переважна більшість мов мають деякі особливості, які важко (якщо не неможливо) статично перевірити. Одним із прикладів є придушення мов. Інші приклади включають арифметичне переповнення, перевірку меж масиву та перевірку нуля. Деякі з них можна статично перевірити за певних обставин, але за великим рахунком, вам важко буде знайти мовну реалізацію, яка не проводить перевірки під час виконання.

Це не погано. Це лише зауваження, що існує багато цікавих властивостей, які ми хотіли б застосувати до наших мов, і що ми не знаємо, як статично перевірити. І це нагадування, що відмінність типу "статичні типи" від "динамічні типи" не є настільки чіткими, як деякі люди вважають, що ви вірите. :)

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


9
"Це просто зауваження, що існує багато цікавих властивостей, які ми хотіли б застосувати нашими мовами, і що ми не знаємо, як статично перевірити". - Ну, це не просто те, що ми не знаємо, як це зробити. « Є ця програма привал для цього входу» є цікавою властивістю , що ми не просто не знаю , як перевірити, але насправді ми робимо знати це неможливо перевірити.
Йорг W Міттаг

"Інші приклади включають арифметичне переповнення, перевірку меж масиву та перевірку нуля." Лише зауважте, що хоча в декількох мовах, які перевіряють ці властивості в системі типів, є декілька мов, навіть у більшості динамічно набраних мов це зазвичай властивість значень , а не типів. (Перевірка "Нуль" є загальною ознакою систем статичного типу.)
porglezomp

Там є динамічний тип системи , і статичний тип системи . Навіть якщо жодне з них не виконується, вони все одно є, описуючи, що правильно, а що - помилка. Мова / реалізація може або не може перевірити жодну з них. До речі, система статичного та динамічного типу повинна відповідати, але це не так за визначенням .
Елазар

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

7

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

Крім того, ви можете це зробити досить легко і в С.

Реакція на інші відповіді: Я думаю, що люди помиляються із статичним / динамічним введенням тексту із сильним / слабким введенням тексту. Динамічне введення тексту - це можливість змінити структуру даних під час виконання, а код може використовувати дані, які просто відповідають тому, що потрібно коду. Це називається Duck Typing .

Згадування рефлексії - це не розповідь всієї історії, оскільки рефлексія не дозволяє змінити існуючу структуру даних. Ви не можете додати нове поле до класу чи структури ні в C, C ++, ні в Java, ні в C #. У динамічних мовах додавання нових полів або атрибутів до існуючих класів не тільки можливо, але насправді є досить поширеним.

Наприклад, подивіться на Cython , компілятор Python-to-C. Він створює статичний код C, але система типів все ще зберігає його динамічний характер. C - це статично набрана мова, але вона здатна підтримувати динамічне введення тексту з Python.


Технічно ви можете це зробити в C #, починаючи з версії 4 ExpandoObject, хоча це дуже корисний процес відбору, на відміну від JavaScript або Ruby. Тим не менш, ви зробили дуже важливий момент, який полягає в тому, що введення качок (що насправді мають на увазі 99% розробників, коли вони говорять, що "динамічно набрали") і рефлексія - це зовсім не те саме.
Aaronaught

Можна також додати, що Python не має справжнього набору качок. У вас просто є гачки, щоб ви "реалізували своє" (є магічний метод, який може повернутися Trueдля того, щоб сказати "цей божевільний об'єкт є екземпляром класу, який я визначаю"). У OCaml є ця особливість, наскільки я розумію, але я насправді не знаю.
vlad-ardelean

6

Динамічні мови - це статичні мови . Те, що прийнято називати "динамічним набором тексту" - це справді особливий випадок статичного набору тексту - випадок, коли ви обмежилися лише одним типом. В якості продуманого експерименту уявіть, що ви пишете програму на Java або C #, використовуючи лише Objectзмінні / поля / параметри та вниз-кастинг безпосередньо перед викликом будь-якого методу. Точніше було б називати такі мови, як Python або Javascript, "об'єднаними". (Ця претензія, швидше за все, бентежить / турбує багатьох людей, оскільки, вважаючи, що така програма Java або C # використовує багато підтипів, але це тому, що середня мова OOP суперечить типам і класам. Докладніше читайте в блозі.)

Зауважте, що навіть на C є "динамічне" введення тексту - ви можете кинути будь-який вказівник на вказівник void(і якщо мені служить пам'ять char), і знову назад. І також зауважте, що там немає перевірки часу виконання; якщо ви помиляєтесь, насолоджуйтесь своєю невизначеною поведінкою!


Але акторський склад робиться статично. Я не бачу, як це є прикладом динамічного набору тексту.
osa

@osa Просто тому, що в коді сказано, String foo = (String) barщо це не означає, що barнасправді є String. Ви можете це точно знати, на час виконання, так що я не бачу, як складання роблять "статично".
Довал

Я не згоден з цим. Принаймні в Javascript ви можете додавати нові методи та властивості до об’єктів під час виконання. У C # для цього потрібно явно використовувати dynamicоб’єкт. Якщо ви спробуєте додати властивість до object... ну, ви не можете.
Артуро Торрес Санчес

3

Різниця між статичним та динамічним введенням полягає в тому, коли перевіряється тип значення: час компіляції та час виконання. У мовах, де значення несуть свій тип із собою (наприклад, об’єкти Java), завжди можна вдатися до динамічного введення тексту, навіть коли мова фактично віддає перевагу статичному введенню. Ось приклад на Java з динамічно набраним методом:

void horribleJava(List untypedList) {
  for (Object o : untypedList)
    ((SpecificType) o).frobnicate();
}

Зверніть увагу, як тип кожного елемента перевіряється під час виконання. Еквівалентним статично типізованим методом є:

void goodJava(List<SpecificType> typedList) {
  for (SpecificType o : typedList) {
    o.forbnicate();
  }
}

У C значення (а конкретно вказівники) не зберігають свого типу під час виконання - кожен покажчик еквівалентний a void *. Натомість змінні та вирази мають тип. Щоб домогтися динамічного введення тексту, вам доведеться самостійно переносити інформацію про тип (наприклад, як поле в структурі).


1
Я не думаю, що акторський склад вважається динамічним набором тексту в будь-якому дійсно практичному сенсі. Він все ще вимагає знань про тип під час компіляції, він просто відкладає фактичну перевірку до виконання. Тут не можна посилатися на frobnicateметод, не знаючи про це SpecificType.
Aaronaught

2
@Aaronaught Але це динамічна типізація , як тільки ми відклали перевірку типу до часу виконання. Зауважте, що в обох моїх прикладах використовується номінативний набір тексту, який потребує конкретного імені типу. Ви думаєте про структурну типізацію , наприклад, набір качок, який вимагає наявності якогось методу. Осі структурного проти номінативного та статичного проти динамічного введення є ортогональними одна для одної (Java номінативний та здебільшого статичний; ML та Go структурні та статичні; Perl, Python та Ruby є (переважно) структурно-динамічними).
амон

Як я вже говорив у своєму останньому коментарі, це теоретична відмінність, яку жоден програміст, якого я ніколи не зустрічав, не хвилює. Можна абразивно стверджувати, що люди використовують неправильну термінологію (і насправді здається, що оригінальний твіттер збирався саме для такої химерності), але для людей, які насправді знаходяться в окопах, динамічне набирання тексту = натискання качки. Насправді це визначення настільки поширене, що такі мови, як C #, насправді кодифікували його (тобто за dynamicключовим словом). Прирівнюючи статичний для компіляції і динамік , щоб у час виконання в основному тільки каламутить воду.
Aaronaught

@Aaronaught: Якщо ви звертаєтесь до інтерфейсу, і якщо класи, які реалізують метод із задуманим значенням, послідовно реалізують один і той же інтерфейс, щоб сказати так, то, по суті, це буде типізація качок, що працює під час виконання. Хоча деякі можуть стверджувати, що для "набору качок" слід просто використовувати назву методу, я думаю, було б корисніше розглянути "справжнє" ім'я методу як ім'я інтерфейсу плюс ім'я методу. В іншому випадку, повинен [1,2].Add([3,4])поступитися [1,2,3,4], [1,2,[3,4]]або [4,6]?
supercat

@supercat: Нічого з вищезазначеного, воно не повинно бути результатом, оскільки Addв масиві немає методу, який би приймав масив, оскільки такий метод був би неоднозначним. Введення качок не виправдає вас від написання зрозумілих типів та функцій.
Aaronaught

2

Статичне проти динамічного введення тексту в основному стосується того, як перевіряються типи. Статичне введення означає, що перевірка типів різних змінних чи виразів перевіряється на основі фактичного коду (зазвичай компілятором), тоді як в динамічній системі типів ця перевірка проводиться лише під час виконання, середовищем виконання.

Я вважаю, що в тексті йдеться про те, що навіть якщо типи перевіряються статично, вони також перевіряються під час виконання, тобто динамічно. Ви правильно згадали Java Reflection; відображення відбувається лише під час виконання, і середовище виконання Java Java (JVM) фактично виконує перевірку типу при використанні відображення, що в основному означає перевірку динамічного типу.


Тоді це не правильно. У C ++, Pascal, Fortran --- на будь-яких мовах, що складаються --- типи перевіряються лише статично, а не динамічно (якщо ви не використовуєте динамический_cast). Ви можете використовувати вказівники для запису довільних матеріалів у пам’ять, і типи ніхто не знатиме. Отже, статичне введення означає ТОЛЬКО ПЕРЕВІРИТИ СТАТИЧНО, тоді як динамічне введення означає ТОЛЬКО ПЕРЕВІРИТИСЯ В РЕЗИМЕНТІ.
osa

-1

Виділення невірно: С також мають важливу систему динамічного типу. Він просто не перевіряє це ("C сильно набрано, слабко перевірено"). Наприклад, трактування структури як double( reinternpret_cast-style) призводить до невизначеної поведінки - помилки динамічного типу.


(Кому хто прихильнився - коментар @Thiago Silva говорить про те саме)
Elazar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.