Статичний / динамічний проти сильного / слабкого


319

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



Відповіді:


423
  • Статичний / Динамічний Typing про коли інформація про типі придбаними (або під час компіляції або під час виконання)

  • Сильне / слабке введення тексту - це те, наскільки суворо розрізняються типи (наприклад, чи намагається мова здійснити неявне перетворення з рядків у числа).

Детальну інформацію див. На Вікі-сторінці .


7
У Вікіпедії є всі відповіді. Чому я вже не натрапив на це, я не знаю.
Ден Ревелл

31
Соромно, що багато хто не усвідомлює, що статичне / динамічне - це щось інше, ніж сильне / слабке ... Це дійсно заощадить деякі упередження та дискусії.
Дікам

10
Існують різні ступені "типової слабкості". Сильно набрана мова може спробувати перетворення з рядків у числа. З іншого боку, HyperTalk (мовою, якою я користувався десятиліття тому) був настільки слабко набраний, що "12" + "34"був би рівним "46", але "12" + "34Q"був би рівним "1234Q"[на щастя, можна було б написати, "12" & "34"якщо хочете конкатенації]. Цікаво, що змінні, що містять числа, зберігають їх як поплавці подвійної точності, і математика на таких змінних використовувала значення з плаваючою комою, не змінюючи рядки, але не було можливості запитати, чи є змінною рядок чи число.
supercat

9
@kittylyst Я не бачу, де ця відповідь говорить про те, що сильний синонім статичного
Піт

4
++ для (приблизно) однорядних визначень.
JamesFaix

211

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

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

Реалізація сильно набраних мов часто набуває лазівки з часом, як правило, щоб частина системи часу роботи могла бути реалізована мовою високого рівня. Наприклад, у Objective Caml є функція, що називається, Obj.magicщо має ефект запуску просто повернути свій аргумент, але під час компіляції він перетворює значення будь-якого типу в будь-який інший тип. Мій улюблений приклад - Модула-3, дизайнери якої назвали свою конструкцію типового лиття LOOPHOLE.

Сказавши це, ви не можете розраховувати на двох людей, що вживають слова "сильний" і "слабкий" точно однаково. Тому уникайте їх.


31
(+1) за вашу пропозицію уникати термінів "сильний" та "слабкий".
Ніко

1
Домовились, якраз читав книгу Джона Скіта, і це той самий відгук, який зазначив там.
Bennett Yeates

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

74

Простіше кажучи так: у мові, що набирається статичним типом, тип є статичним , тобто після встановлення змінної типу ви НЕ МОЖЕТЕ її змінити. Це тому, що типізація пов'язана зі змінною, а не зі значенням, на яке вона посилається.

Наприклад, на Java:

String str = "Hello";  //statically typed as string
str = 5;               //would throw an error since java is statically typed

Якщо в динамічно набраній мові тип є динамічним , тобто після встановлення змінної типу ви МОЖЕТЕ її змінити. Це тому, що типізація пов'язана зі значенням, а не змінною.

Наприклад в Python:

str = "Hello" # it is a string
str = 5       # now it is an integer; perfectly OK

З іншого боку, сильне / слабке введення мовою пов'язане з неявними перетвореннями (частково взяті з відповіді @ Даріо):

Наприклад в Python:

str = 5 + "hello" 
# would throw an error since it does not want to cast one type to the other implicitly. 

тоді як в PHP:

$str = 5 + "hello"; // equals 5 because "hello" is implicitly casted to 0 
// PHP is weakly typed, thus is a very forgiving language.

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


2
чудова відповідь та кудо за використання конкретних прикладів.
Джуліан А.

3
Ось чому PHP потрібно використовувати дуже обережно.
Алі Гаджані

1
Мовні приклади дуже корисні. Цінується.
Дж. Маллен

У цьому сенсі чи буде Java колись настільки слабко набрана, тому що ви можете об'єднати рядки з рядками і через автоматичне розпакування / бокс?
Стівен Пол

1
@StephenPaul ви праві, мою відповідь можна зрозуміти таким чином, і це не так. Я використовував конкатенацію заради простоти, але насправді сильність / слабкість стосується неявного перетворення типу змінної.
mehmet

20

Слабке введення означає, що тип об'єкта може змінюватися залежно від контексту. Наприклад, слабо набраною мовою рядок "123" може трактуватися як число 123, якщо додати до нього ще одне число. Прикладами мов зі слабким набором тексту є bash, awk та PHP.

Інший різновид слабо типізованої мови - це C, де дані за адресою пам'яті можна розглядати як інший тип шляхом лиття.

У сильно набраній мові тип об’єкта не змінюється - int - це завжди int і намагання використовувати його як рядок призведе до помилки. І Java, і Python сильно набрані.

Різниця між динамічною та статичною типізацією полягає у застосуванні правил типу. Статично набраною мовою тип кожної змінної та параметра повинен бути оголошений у джерелі та застосований під час компіляції. У динамічно набраній мові типи перевіряються лише тоді, коли вони використовуються під час виконання. Таким чином, Java набирається статично і Python динамічно набирається.

Однак межі часом можуть бути трохи розмитими. Наприклад, хоча Java набирається статично, щоразу, коли ви використовуєте відображення або кастинг (наприклад, при використанні контейнерів Об'єктів), вони відкладають перевірку типу на час виконання.

Аналогічно більш сильно набрані мови все ще автоматично перетворяться між цілими числами і плавцями (а в деяких мовах атриторна точність BigInts).


1
Я не можу погодитися з цим реченням -. "У статично введеній мові тип кожної змінної та параметра повинен бути оголошений у джерелі" - у SML типи змінних не повинні бути оголошені (як ніколи вони перевіряються). Скажімо, функція fбере аргумент x( fun f(x)) [**, тому типи не оголошуються **], а тіло функції є x+1. Без типів оголошеного компілятора з'ясується, що xвін повинен бути цілим. - fun f x = x + 1; val f = fn : int -> int
Філіп Бартузі

Що стосується C, то кастинг не проти сильного набору тексту, але C дозволяє додавати різні типи, не надсилаючи їх, наприклад:5 + 'c' // OK
mehmet

3
@mehmet: у C значення символів знаходяться в цілій області, так що конкретний приклад не порушує безпеку типу. 'c' - це просто синтаксичний цукор для 99. C не має виділеного типу символів.
Пітер Леверін

Пітер Леверін: правильно, я мав би дати кращий приклад. На жаль, минуло майже 20 років, як я не торкнувся С :)
mehmet

1
З не слабо типізованою мовою . Просто Java, C # тощо є більш сильно набраними мовами порівняно з C. Детальніше тут - en.wikipedia.org/wiki/Strong_and_weak_typing Якщо ви перевіряєте визначення "слабо" введеної мови, то "слабо" введені мови це ті, в яких можна здійснити будь-який тип перетворення, наприклад, int можна "неявно" перетворити або закинути в рядок, тепер подумайте самі, чи можливо це в C чи ні?
hagrawal

15

Сьогодні, вивчаючи цю тему, я натрапив на цю чудову статтю http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html Це очистило багато речі для мене, і я думав, що це може додати до деяких чудових відповідей вище.

Сильний і слабкий набір тексту:

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

Статичні та динамічні типи

Це майже єдина поширена класифікація типів систем, яка має реальне значення. Власне кажучи, його значення часто недооцінюється [...] Динамічні та статичні системи - це дві абсолютно різні речі, цілі яких частково перекриваються.

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

Явні / неявні типи:

Коли ці терміни використовуються, вони посилаються на те, наскільки компілятор буде міркувати про статичні типи частин програми. Усі мови програмування мають певну форму міркування про типи. Деякі мають більше, ніж інші. ML та Haskell мають неявні типи, оскільки декларації типу не потрібні (або дуже мало, залежно від мови та розширень, що використовуються). Java та Ada мають дуже явні типи, і один постійно декларує типи речей. Усі вищезазначені мають (відносно порівняно, наприклад, С та С ++) сильні системи статичного типу.


8

З Прагматики мови програмування Скотта , сторінка 291, 3-е видання, у нас є

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

Кілька прикладів: Ада сильно набрана та здебільшого статично набрана (певні обмеження типу необхідно перевіряти під час виконання). Реалізація Pascal також може виконати більшість перевірених типів під час компіляції, хоча мова не надто сильно набрана: незаписані варіанти записів (обговорюються в розділі 7.3.4) - єдина її лазівка. C89 значно сильніше набраний, ніж діалекти попередників, але все ж значно менш сильно набраний, ніж Паскаль. Його лазівки включають об'єднання, підпрограми із змінними числами параметрів та сумісність покажчиків та масивів (обговорюється в розділі 7.7.1). Реалізація C рідко перевіряє що-небудь під час виконання.

Динамічна перевірка (час виконання) - це форма пізнього прив'язки, і вона має тенденцію знаходитися на мовах, які затримують інші проблеми до часу виконання. Lisp і Smalltalk набираються динамічно (хоча і сильно). Більшість мов сценаріїв також динамічно набираються; деякі (наприклад, Python та Ruby) сильно набрані. Мови з динамічним масштабуванням, як правило, динамічно набираються (або взагалі не набираються): якщо компілятор не може ідентифікувати об'єкт, на який посилається ім'я, він також не може визначити тип об'єкта.

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

Я спробував перевести опис Скотта в приємну схему, яку я розмістив нижче.

Статична / динамічна - сильна / слабка набрана площина


5

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

Ось два приклади:

  • Деякі кажуть, що Haskell сильно набраний, тому що вам не дозволяється робити якісь перетворення.

  • Інші (наприклад, погляд Даріо) говорять, що мова, яка дозволяє неявно перетворювати з рядка в число за призначенням, набрана слабко, але навіть інші називають це просто набиранням качки.

Обидва твердження підкреслюють не протилежні крайності типової системи, а зовсім інші аспекти. Тож я приєднуюся до думки містера Рамзі не використовувати терміни "сильний" і "слабкий" для розмежування систем типів.


5

Статично v / s динамічно набрані мови

  • Статично типізовані мови - це ті, у яких перевірка типів проводиться під час компіляції, тому це також означає, що в статично набраних мовах кожна змінна має тип і вона не змінюється протягом курсу. Тепер, навпаки, динамічно типізовані мови - це ті, у яких перевірка типів виконується під час виконання, і не відбувається перевірка типів під час компіляції, тому це також означає, що в динамічно набраних мовах може бути або не бути типу, пов'язаного зі змінними , а якщо тип асоційований, то це може бути такий загальний тип, як "var" в JS, який відповідає як рядку, так і номеру.
    • "Реалізація динамічно перевірених типів мов зазвичай пов'язує кожен об'єкт виконання з тегом типу (тобто посиланням на тип), що містить інформацію про його тип. Ця інформація типу виконання (RTTI) також може бути використана для реалізації динамічної диспетчеризації, пізнього прив'язки, лиття вниз, відбиття та подібні функції ".
  • Навіть якщо мова є статично набраною, вона все-таки може мати деяку динамічно набрану функцію, що в основному означає, що також якась перевірка типу під час виконання. Це корисно при кастингу типів.
    • "Ряд корисних і поширених функцій мови програмування неможливо перевірити статично, наприклад, вниз на лиття. Таким чином, багато мов матимуть як статичну, так і динамічну перевірку типу; статична перевірка типу перевіряє, що вона може, а динамічна перевірка підтверджує решту ».
  • "Деякі мови дозволяють писати код, який не є безпечним для типу. Наприклад, на C програмісти можуть вільно передавати значення між будь-якими двома типами, які мають однаковий розмір. "
  • Перевагами "статично" набраних мов є те, що:
    • Оскільки більшість перевірок типу проводиться під час компіляції, то інтерпретатор або час виконання може працювати на повній швидкості, не турбуючись про типи.
    • Це призводить до меншої кількості виключень під час виконання або помилок, пов’язаних із типом, оскільки більшість перевірок типу проводиться під час компіляції.
  • Перевагами "динамічно" набраних мов є те, що:
    • Вони можуть допомогти у надзвичайно швидкому прототипуванні, оскільки розробникові не потрібно розуміти тип системи, тому розробник може вільно створювати змінні та запускати його, а це призводить до дуже швидкого прототипування.
  • Перелік статично та динамічно набраних мов :
    • Статично:
      • Java
      • C (C - статично набрана мова, але менша кількість "сильно" набрана порівняно з Java, оскільки вона дозволяє більш неявні перетворення)
      • C ++
      • C #
    • Динамічно:
      • PERL
      • PHP
      • Пітон
      • JavaScript
      • Рубін
  • Перевірка типу - важлива функція безпеки. Припустимо, немає перевірки типу, і метод приймає об'єкт типу "BankAccount", який має метод, який називається "CreditAccount (BankAccountDetails)", тепер під час виконання, якщо немає перевірки типу, я можу передавати власний об'єкт клас, який має той самий метод "CreditAccount (BankAccountDetails)", і він буде виконуватися, враховуючи, що ми говоримо про об'єктно-орієнтовану мову, оскільки OOP підтримує "поліморфізм", і тут те, що ми обговорюємо, є не що інше, як "поліморфізм". Отже, в основному об'єктно-орієнтована мова (що в основному означає, що вона підтримує «поліморфізм»), яка не має чіткої перевірки типу, може призвести до проблем безпеки.

Сильно в / с слабо набрані мови

  • Сильно набрані мови - це ті, в яких неявні перетворення не допускаються, якщо є втрата точності. Наприклад, в Java ви можете надати "int to long", оскільки втрати точності немає, але ви не можете "неявно" віддати "long to int", тому що буде втрата точності. Навпаки, у слабко набраних мовах неявні перетворення допускаються, навіть якщо є втрата точності.
  • Я думаю, що динамічно набрана мова також може бути сильно набраною мовою, якщо "під час виконання" вона не дозволяє неявних перетворень, в яких є втрата точності.

Гарні подальші читання


Ви цитували "зараз під час виконання, якщо немає перевірки типу, я можу передати об'єкт власного класу, який має той самий метод" CreditAccount (BankAccountDetails) "- якщо ви вже перевершили механізм, який міг би перешкодити вам передати об'єкт Тоді як перевірка типу не дозволить вам викликати цей метод у випадку статично введеної мови?
Асеем Ядав

@AseemYadav Що ви маєте на увазі під "*, якщо ви вже перевершили механізм, який міг би перешкодити вам передати об'єкт *"?
hagrawal

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

У цьому немає жодного аспекту продуктивності, ви повинні бачити це з контексту поліморфізму, тоді ви зможете зрозуміти аспект його безпеки, про це я вже згадував у цьому ж пункті.
hagrawal

1

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

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

Елементи статично та динамічно набраних мов можна комбінувати. Наприклад, C # підтримує як статично, так і динамічно набрані змінні, а об'єктно-орієнтовані мови, як правило, підтримують ієрархію типів вниз. Статично типізовані мови зазвичай надають різні способи обходу перевірки типів, наприклад, за допомогою кастингу, відображення та динамічного виклику.

Сильний проти слабкого набору тексту стосується континууму того, наскільки мова намагається запобігти помилкам через використання змінної, як якщо б це був один тип, коли він насправді іншого типу. Наприклад, і C, і Java є типово типізованими мовами, однак Java використовує набагато сильнішу перевірку типу, ніж C. Наступний код C із задоволенням збирає та запускає, і він вводить випадкове значення у змінну b під час виконання, швидше за все, спричиняючи помилка:

char *a = "123";
int b = (int)a;

Еквівалентний код Java створює помилку компіляції, яка, як правило, є кращою:

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