Що таке надмірний приклад статичної перевірки типу занадто консервативного?


9

У поняттях з мов програмування Джон Мітчелл пише, що перевірка статичного типу обов'язково консервативна (надто сувора) через проблему зупинки. Він наводить як приклад:

if (complicated-expression-that-could-run-forever)
   then (expression-with-type-error)
   else (expression-with-type-error)

Чи може хтось надати неспростову відповідь, яка б насправді була проблемою?

Я розумію, що Java дозволяє динамічно перевіряти касти для таких випадків:

if (foo instanceof Person) {
    Person p = (Person) foo;
    :
}

але я вважаю необхідністю більше дефіциту мови / компілятора Java, ніж мовної мови.


2
Приклад Java, який ви навели, - це не надуманий приклад статичної перевірки типу занадто консервативного характеру. По-іншому: відповідь залежить від того, яку систему ви пам’ятаєте. У будь-якому прикладі, який ми придумаємо, завжди буде система типів, яка може обробляти цей приклад (система типу не надто консервативна на цьому прикладі). Для будь-якої системи типів ми завжди можемо знайти приклад, коли вона занадто консервативна. Отже, я думаю, вам потрібно вказати систему типів. Якщо система типу Java - це не те, що ви мали на увазі, чи існує щось більш конкретне, про що ви думали? Висновок типу ML?
DW

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

Відповіді:


7

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

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

Ось кілька прикладів методів структурування програм, якими іноді вважається, що їх легше керувати динамічно, ніж мови, які мають статичний тип.

Дженерики та контейнери

Статично типізованими мовами до ML (c. 1973) та CLU (c. 1974) було важко створити червоно-чорне дерево струн, червоно-чорне дерево цілих чисел, червоно-чорне дерево плавців або червоно-чорне дерево елементів конкретного типу Foo. Однак було важко (можливо, неможливо) створити єдину реалізацію червоно-чорного дерева, яке було статистично перевірено і яке могло б обробляти будь-який із цих типів даних. Шляхи вирішення проблеми полягали в тому, щоб (1) повністю вийти з системи типу (наприклад: за допомогоюvoid * в C), (2) написати собі якийсь макропрепроцесор, а потім записати макроси, які створюють код для кожного конкретного типу, який ви хочете, або (3) використовувати підхід Lisp / Smalltalk (і Java) для перевірки типу видобутого об'єкт динамічно.

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

Підтип поліморфізму

У статично типових мовах до Simula67 (c. 1967) та Hope (c. 1977) не вдалося як зробити динамічну розсилку, так і статично перевірити, чи охоплювали ви справу для кожного підтипу. Багато мови мали деяку форму мічених спілок , але це було обов'язком програміста , щоб переконатися , що їх caseабо switchзаяви, або їх таблиці стрибати, усі позакривали можливий тег.

Мови, що слідують за моделлю Simula (C ++, Java, C #, Eiffel), надають абстрактні класи з підкласом, де компілятор може перевірити, чи кожен підклас реалізував усі методи, оголошені батьківським класом. Мови, що слідують за моделлю Hope (всі варіанти ML, від SML / NJ до Haskell), мають алгебраїчні підтипи, де компілятор може перевірити, що кожне typecaseтвердження охоплює всі підтипи.

Виправлення мавп та орієнтоване на аспекти програмування

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

Хоча існують очевидні способи, за допомогою яких виправлення мавп можна використовувати, щоб зробити програми важче підтримувати, але існують також способи, якими він може бути використаний для "добра", а не для "зла". Зокрема, в аспектно-орієнтованому програмуванні можна використовувати подібні методи виправлення мавп, щоб зробити такі речі, як змінити тип файлу, щоб вказати на віртуалізовану файлову систему, дозволяючи будувати інфраструктури для тестування одиниць для "вільних" або змінювати прості типи виключень, щоб вони друкувати повідомлення журналу щоразу, коли вони потрапляють для кращої налагодження.

На відміну від генерики та підтипу поліморфізму, де ключові ідеї статичної перевірки були доступні у 1970-х, статична перевірка аспектно-орієнтованого програмування є (я думаю) активною дослідницькою сферою. Я мало що про це знаю, за винятком того, що з 2001 року існує мова під назвою AspectJ .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.