Яка різниця між сильно набраною мовою та мовою статичного типу?


Відповіді:


542

Яка різниця між сильно набраною мовою та мовою статичного типу?

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

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

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

Протилежність статично типізованому "динамічно набрана", що означає, що

  1. Значення, використані під час виконання, класифікуються на типи.
  2. Існують обмеження щодо використання таких значень.
  3. Якщо ці обмеження порушуються, про порушення повідомляється як (динамічна) помилка типу.

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

Сильний проти слабкий

Протилежність "сильно набраному" - "слабо набране", що означає, що ви можете обійти систему типу. C, як відомо, слабо типізований, оскільки будь-який тип вказівника може бути конвертований у будь-який інший тип вказівника просто шляхом кастингу. Паскаль мав бути сильно набраний, але нагляд за дизайном (без тегів записів варіантів) ввів лазівку в систему типів, так що технічно вона набрана слабко. Приклади справді сильно набраних мов включають CLU, Standard ML та Haskell. Фактично МЛ фактично зазнав декількох змін, щоб усунути проломи в системі типів, які були виявлені після широко розгорнутої мови.

Що насправді відбувається тут?

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

  • Аматори часто пов'язують їх із "статичним" та "динамічним".

  • Очевидно, "слабкий набір тексту" деякі люди використовують для того, щоб говорити про відносну переважність або відсутність неявних перетворень.

  • Професіонали не можуть погодитись, що саме означають терміни.

  • Загалом ви навряд чи інформуєте або просвітлите свою аудиторію.

Сумна правда полягає в тому, що якщо говорити про типові системи, то "сильні" і "слабкі" не мають загальновизнаного технічного значення. Якщо ви хочете обговорити відносну міцність типних систем, краще обговорити, які саме гарантії є, а що не надаються. Наприклад, хорошим питанням є таке: "чи гарантоване кожне значення даного типу (або класу), створене за допомогою виклику одного з конструкторів цього типу?" У С відповідь - ні. У CLU, F # та Haskell це так. Що стосується C ++, я не впевнений - я хотів би знати.

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

Чи має на увазі одне інше?

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

  • Вони (неправильно) використовують "сильний" і "слабкий", щоб означати "статичний" і "динамічний", і в цьому випадку вони (неправильно) використовують взаємозамінно "сильно набрані" та "статично типізовані".

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

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


3
@Adam: Очевидно, недостатньо правильний, щоб бути схваленим :) Оскільки відповідь Клетуса містить стільки неправильних уявлень (хоча я редагував найгірші з них), я відчував вимушеність прописати все словами одним складом ...
Норман Рамзі,

1
Що ж, я підтримав вас :) Навіть слово "компілювати" не є чітким, коли сучасні віртуальні машини працюють з динамічними мовами. Технічно Java і C # обидва складаються двічі (JIT) і обидва роблять певний аналіз. Мова на зразок Javascript, що працює в .NET vm, може бути більше Typesafe через VM.
Адам Гент

2
Я зараз так розгублений! Гаразд, дорогі великі гладіатори арени, чи може бідна душа, як я, піти з таким простим розумінням? 1.Static: Значення асоціюються з типом під час компіляції, а не час запуску.2.Dynamic: Значення пов'язані з типом під час виконання, отже, тип значення може змінюватися під час виконання ~ тому більш схильний до питань, пов’язаних з кастингом під час виконання. 3. Сильний / слабкий: Забудь! Це не технічні терміни, а просто погана номенклатура. Це залежить від того, про який контекст йдеться. Чи можу я продовжувати своє життя з таким простим розумінням? :(
Saurabh Patil

"чи гарантується, що кожне значення даного типу (або класу) було створене за допомогою виклику одного з конструкторів цього типу?" У С відповідь - ні. Чи може хтось навести приклад ситуації, коли це відбувається в C? Я припускаю, що це передбачає виведення покажчиків на структури?
corazza

Сильний і слабкий набір тексту: такої класифікації немає.
Рауль

248

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

Статичне / динамічне введення тексту

Статичне введення - це те, де тип пов'язаний зі змінною . Типи перевіряються під час компіляції.

Динамічне введення - це тип, який пов'язаний зі значенням . Типи перевіряються під час виконання.

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

String s = "abcd";

sбуде "назавжди" а String. Протягом свого життя це може вказувати на різні Strings (оскільки sце посилання на Java). Це може мати nullзначення, але воно ніколи не стосуватиметься Integerабо a List. Це статичне введення тексту.

На PHP:

$s = "abcd";          // $s is a string
$s = 123;             // $s is now an integer
$s = array(1, 2, 3);  // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class

Це динамічний набір тексту.

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

(Редагувати попередження!)

Сильне введення тексту - це фраза, яка не має широкого узгодженого значення Більшість програмістів, які використовують цей термін, щоб означати щось інше, ніж статичне введення тексту, використовують його для того, щоб зрозуміти, що існує дисципліна типу, яка застосовується компілятором. Наприклад, CLU має систему сильного типу, яка не дозволяє клієнтському коду створювати значення абстрактного типу, за винятком використання конструкторів, наданих цим типом. C має дещо сильну систему типів, але її можна "перекрутити" на ступінь, оскільки програма завжди може передавати значення одного типу вказівника до значення іншого типу вказівника. Так, наприклад, в C ви можете взяти значення, повернене malloc()і радісно передавати його FILE*, і компілятор не намагатиметься зупинити вас - або навіть попередити вас, що ви робите що-небудь хитке.

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

Слабке введення означає, що компілятор не застосовує набір тексту, або можливо, що примусове виконання може бути легко зірвано.

Оригінал цієї відповіді поєднував слабке введення тексту з неявним перетворенням (іноді його також називають «неявна промоція»). Наприклад, на Java:

String s = "abc" + 123; // "abc123";

Цей код є прикладом неявного просування: 123 неявно перетворюється на рядок перед тим, як з'єднуватися з "abc". Можна стверджувати, що компілятор Java переписує цей код як:

String s = "abc" + new Integer(123).toString();

Розглянемо класичну проблему PHP "починається з":

if (strpos('abcdef', 'abc') == false) {
  // not found
}

Помилка тут полягає в тому, що strpos()повертає індекс матчу, який дорівнює 0. 0, примушують бути булевим falseі, отже, умова справді відповідає дійсності. Рішення - використовувати ===замість того, ==щоб уникнути неявного перетворення.

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

Порівняйте це з Ruby:

val = "abc" + 123

що є помилкою виконання, оскільки в Ruby об'єкт 123 неявно не перетворюється лише через те, що він передається +методу. У Ruby програміст повинен зробити перетворення явним:

val = "abc" + 123.to_s

Порівняння PHP та Ruby - хороша ілюстрація тут. Обидва є динамічно набраними мовами, але PHP має безліч неявних перетворень, і Ruby (можливо, дивно, якщо ви з ним незнайомі).

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

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

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

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

Але важливо розуміти, що мова може бути статичною / сильною, статичною / слабкою, динамічною / сильною або динамічною / слабкою.


Замість того, щоб говорити $ s - це ціле число або рядок, було б краще, якщо ви скажете, що тип асоціюється з "abcd" або 1234, а не зі змінною $ s.
Шрінівас Редді Татіпарті

Відмінна відповідь з чіткими прикладами. Однак, я думаю, це не повністю стосується плутанини щодо того, Чому люди запитують про сильне / статичне як про дві концепції. Наприклад, формулювання ОП про те, "чи статичне введення НЕЗАБАВЛЬНО сильно вводить текст?" Ваша відповідь підкреслює їх незалежність. Щоб продовжити роз'яснення того , чому сильні часто PAIRED зі статичними, попередній відповідь Нормана Ремсі дуже добре: stackoverflow.com/questions/376611 / ...
JasDev

1
"abc" + 123- це помилка виконання , а не помилка компіляції в рубіні. Якби це була помилка компіляції, рубін був би статично набраний.
sepp2k

Слабкі приклади введення тексту потрібно вдосконалити (див. Мою відповідь), але в іншому випадку приємне форматування.
Адам Гент

На мій погляд, сильний та слабкий типін є таким: Сильний: "c" + True = помилка виконання або помилка часу компіляції. Слабкий: "c" + True = "b" або "d", тому що все трактується як необроблені байти. Сильний: C #, Ruby, C ++ Слабкий: Асамблея, C (через неявні покажчики недійсності)
Джонатан Аллен,

17

Обидва є полюсами на двох різних осях:

  • сильно набрано проти слабо набране
  • статично типізований та динамічно набраний

Сильно набраний засіб не буде автоматично перетворюватися з одного типу в інший. Слабо набране протилежне: Perl може використовувати рядок, як "123"у числовому контексті, автоматично перетворюючи його в int 123. Сильно набрана мова, як python, цього не зробить.

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


6
Я повинен не погодитися. Сильно набрана мова - це мова, яка знає, які типи є під час виконання. Слабо набрана мова - це мова, яка не любить зборів. Ваш приклад на третій осі, "неявна проти явної конверсії".
Джонатан Аллен

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

1
Python - приклад динамічно набраної та сильно набраної мови
MaRoBet

13

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


Щоб продемонструвати це: У сильно набраній мові ви не можете порівняти "5" == 5 і визнати це правдою: рядки не є цілими числами. Якщо моя пам'ять служить, більшість сучасних мов сценаріїв сильно динамічно набираються. Tcl / Tk, однак слабко набраний - все можна розглядати як рядок.
Столики маленького бобіка

Бобі, слабко набраною мовою "5" == 5 читається як 0x35 == 0x05. Або іншими словами, все трактується як сирі байти.
Джонатан Аллен

Я повинен погодитися з вами обома. Візьміть Луа; ви можете порівняти "5" == 5, і воно повернеться помилковим, проте швидке перетворення можна здійснити, перейшовши на "5" + 0.
RCIX

12

Даний примус не обов'язково означає слабо типізований, оскільки іноді його синтаксичний цукор:

Наведений вище приклад щодо того, що Java набрано слабко через

String s = "abc" + 123;

Приклад не є слабким типом, тому що він справді робить:

String s = "abc" + new Integer(123).toString()

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

Це на відміну від C. C - один з найкращих прикладів слабо типізованих. Виконання не має поняття, якщо 4 байти - це ціле число, структура, вказівник або 4 символи.

Час виконання мови дійсно визначає, чи є її слабкою типовістю, інакше її дійсно справедливою думкою.

EDIT: Після подальшої думки це не обов'язково відповідає дійсності, оскільки час виконання не повинен мати усі типи перероблених в системі виконання, щоб бути сильно набраною системою. Haskell і ML мають настільки повний статичний аналіз, що вони можуть потенційно опускати інформацію типу під час виконання.


B, мабуть, кращий, якщо трохи менш відомий, наприклад.
Том Хотін - тайклін

Javascript також досить слабкий тип, але через те, що таких типів дуже мало і тому що ви не можете створити нові типи.
Адам Гент

10

Відповідь вже дана вище. Намагаємось розмежувати концепцію сильного проти тижня та статичного проти динамічного.

Що сильно набрано VS Слабо набрано?

Сильно набрано: не буде автоматично перетворено з одного типу в інший

У Go або Python подібні сильно набрані мови "2" + 8 призведе до помилки типу, оскільки вони не дозволяють "ввести примус".

Слабо (нещільно) набрано: буде автоматично перетворено в один тип до іншого: Слабо набрані мови, такі як JavaScript або Perl, не видадуть помилки, і в цьому випадку JavaScript призведе до "28", а perl - 10.

Приклад Perl:

my $a = "2" + 8;
print $a,"\n";

Збережіть його в main.pl і запустіть, perl main.plі ви отримаєте вихід 10.

Що таке статичний тип VS Dynamic?

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

  • Статичний: типи перевірені перед запуском
  • Динамічний: типи, що перевіряються на льоту, під час виконання

Що це означає?

У програмі Go it перевіряються набрані до запуску (статична перевірка). Це означає, що він не тільки переводить і перевіряє тип коду, який він виконує, але він буде перевіряти весь код і помилку типу буде викинуто до того, як код навіть буде запущений. Наприклад,

package main

import "fmt"

func foo(a int) {
    if (a > 0) {
        fmt.Println("I am feeling lucky (maybe).")
    } else {
        fmt.Println("2" + 8)
    }
}

func main() {
    foo(2)
}

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

go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)

Але цей випадок не дійсний для Python. Наприклад, наступний блок коду буде виконуватись для першого виклику foo (2), а для другого виходу foo (0) - невдалий. Це тому, що Python динамічно набирається, він лише переводить і перевіряє код, який він виконує. Інший блок ніколи не виконується для foo (2), тому "2" + 8 ніколи навіть не дивився, а для виклику foo (0) він спробує виконати цей блок і не вдався.

def foo(a):
    if a > 0:
        print 'I am feeling lucky.'
    else:
        print "2" + 8
foo(2)
foo(0)

Ви побачите наступний вихід

python main.py
I am feeling lucky.
Traceback (most recent call last):
  File "pyth.py", line 7, in <module>
    foo(0)
  File "pyth.py", line 5, in foo
    print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects

8

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

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


7

Сильне введення тексту, ймовірно, означає, що змінні мають чітко визначений тип і що існують суворі правила щодо поєднання змінних різних типів у виразах. Наприклад, якщо A є цілим числом, а B - поплавком, то суворим правилом щодо A + B може бути те, що A передається до поплавця, а результат повертається як поплавок. Якщо A - ціле число, а B - рядок, то суворим правилом може бути те, що A + B недійсне.

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

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

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

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