Відповіді:
Яка різниця між сильно набраною мовою та мовою статичного типу?
Статично набрана мова має систему типів, яка перевіряється в час компіляції реалізацією (компілятором або інтерпретатором). Перевірка типу відхиляє деякі програми, а програми, які проходять перевірку, зазвичай мають деякі гарантії; наприклад, компілятор гарантує не використовувати цілі арифметичні вказівки щодо чисел з плаваючою комою.
Немає реальної згоди щодо того, що означає "сильно набраний", хоча найпоширенішим визначенням у професійній літературі є те, що "сильно набраною" мовою програміст не може обійти обмеження, накладені системою типів . Цей термін майже завжди використовується для опису мов, що мають статичний тип.
Протилежність статично типізованому "динамічно набрана", що означає, що
Наприклад, Lua , мова, що динамічно набирається, має ряд рядків, тип чисел та булевий тип. У Lua кожне значення належить точно одному типу, але це не вимога для всіх динамічно набраних мов. У Луа дозволено об'єднати два рядки, але не допустимо об'єднати рядок і булеве.
Протилежність "сильно набраному" - "слабо набране", що означає, що ви можете обійти систему типу. C, як відомо, слабо типізований, оскільки будь-який тип вказівника може бути конвертований у будь-який інший тип вказівника просто шляхом кастингу. Паскаль мав бути сильно набраний, але нагляд за дизайном (без тегів записів варіантів) ввів лазівку в систему типів, так що технічно вона набрана слабко. Приклади справді сильно набраних мов включають CLU, Standard ML та Haskell. Фактично МЛ фактично зазнав декількох змін, щоб усунути проломи в системі типів, які були виявлені після широко розгорнутої мови.
В цілому, виявляється, не так корисно говорити про "сильних" і "слабких". Чи є у типової системи лазівка менш важлива, ніж точна кількість та характер бійниць, наскільки ймовірні вони виникнуть на практиці та які наслідки експлуатації лазівки. На практиці найкраще взагалі уникати термінів "сильний" і "слабкий" , оскільки
Аматори часто пов'язують їх із "статичним" та "динамічним".
Очевидно, "слабкий набір тексту" деякі люди використовують для того, щоб говорити про відносну переважність або відсутність неявних перетворень.
Професіонали не можуть погодитись, що саме означають терміни.
Загалом ви навряд чи інформуєте або просвітлите свою аудиторію.
Сумна правда полягає в тому, що якщо говорити про типові системи, то "сильні" і "слабкі" не мають загальновизнаного технічного значення. Якщо ви хочете обговорити відносну міцність типних систем, краще обговорити, які саме гарантії є, а що не надаються. Наприклад, хорошим питанням є таке: "чи гарантоване кожне значення даного типу (або класу), створене за допомогою виклику одного з конструкторів цього типу?" У С відповідь - ні. У CLU, F # та Haskell це так. Що стосується C ++, я не впевнений - я хотів би знати.
Навпаки, статичне введення означає, що програми перевіряються перед їх виконанням , а програма може бути відхилена перед її запуском. Динамічне введення означає, що типи значень перевіряються під час виконання, і неправильно набрана операція може призвести до того, що програма зупинить або іншим чином подає сигнал про помилку під час виконання. Основною причиною статичного набору тексту є виключення програм, які можуть мати такі "помилки динамічного типу".
Чи має на увазі одне інше?
На педантичному рівні ні, тому що слово "сильний" насправді нічого не означає. Але на практиці люди майже завжди роблять одну з двох речей:
Вони (неправильно) використовують "сильний" і "слабкий", щоб означати "статичний" і "динамічний", і в цьому випадку вони (неправильно) використовують взаємозамінно "сильно набрані" та "статично типізовані".
Вони використовують "сильний" і "слабкий" для порівняння властивостей систем статичного типу. Дуже рідко чути, як хтось говорить про "сильну" чи "слабку" систему динамічного типу. За винятком FORTH, який насправді не має якоїсь типової системи, я не можу придумати динамічно набрану мову, де система типів може бути перетворена. Начебто за визначенням, ці перевірки об'єднуються в двигун виконання, і кожна операція перевіряється на надійність перед виконанням.
У будь-якому разі, якщо людина називає мову "сильно набраною", ця людина, ймовірно, говорить про статично набрану мову.
Це часто неправильно зрозуміло, тому дозвольте мені прояснити це.
Статичне введення - це те, де тип пов'язаний зі змінною . Типи перевіряються під час компіляції.
Динамічне введення - це тип, який пов'язаний зі значенням . Типи перевіряються під час виконання.
Так на Java, наприклад:
String s = "abcd";
s
буде "назавжди" а String
. Протягом свого життя це може вказувати на різні String
s (оскільки 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 (можливо, дивно, якщо ви з ним незнайомі).
Справа в тому, що статична / динамічна вісь не залежить від сильної / слабкої осі. Люди плутають їх, ймовірно, частково, тому що типізація сильних проти слабких не тільки менш чітко визначена, немає реального консенсусу щодо того, що саме означає "сильний і слабкий". З цієї причини сильне / слабке введення тексту набагато більше відтінку сірого, а не чорного або білого.
Отже, щоб відповісти на ваше запитання: ще один спосіб переглянути це, що є найбільш правильним, - сказати, що статичне введення - це безпека типу компіляції, а сильне введення тексту - безпека типу виконання.
Причиною цього є те, що змінні в статично набраній мові мають тип, який повинен бути оголошений і який можна перевірити під час компіляції. Сильно типізована мова має значення, які мають тип під час виконання, і програмісту важко підривати систему типів без динамічної перевірки.
Але важливо розуміти, що мова може бути статичною / сильною, статичною / слабкою, динамічною / сильною або динамічною / слабкою.
"abc" + 123
- це помилка виконання , а не помилка компіляції в рубіні. Якби це була помилка компіляції, рубін був би статично набраний.
Обидва є полюсами на двох різних осях:
Сильно набраний засіб не буде автоматично перетворюватися з одного типу в інший. Слабо набране протилежне: Perl може використовувати рядок, як "123"
у числовому контексті, автоматично перетворюючи його в int 123
. Сильно набрана мова, як python, цього не зробить.
Статично набраний означає, що компілятор визначає тип кожної змінної під час компіляції. Мови, що динамічно вводяться, з'ясовують лише типи змінних під час виконання.
Сильно набраний означає, що між перетвореннями між типами існують обмеження. Статично введене означає, що типи не є динамічними - ви не можете змінити тип змінної після її створення.
Даний примус не обов'язково означає слабо типізований, оскільки іноді його синтаксичний цукор:
Наведений вище приклад щодо того, що Java набрано слабко через
String s = "abc" + 123;
Приклад не є слабким типом, тому що він справді робить:
String s = "abc" + new Integer(123).toString()
Примус даних також не надруковано, якщо ви створюєте новий об'єкт. Java - це дуже поганий приклад слабо набраного тексту (і будь-яка мова, яка має гарне відображення, швидше за все, не буде набрана слабко). Тому що час виконання мови завжди знає, що це за тип (виняток можуть бути рідні типи).
Це на відміну від C. C - один з найкращих прикладів слабо типізованих. Виконання не має поняття, якщо 4 байти - це ціле число, структура, вказівник або 4 символи.
Час виконання мови дійсно визначає, чи є її слабкою типовістю, інакше її дійсно справедливою думкою.
EDIT: Після подальшої думки це не обов'язково відповідає дійсності, оскільки час виконання не повинен мати усі типи перероблених в системі виконання, щоб бути сильно набраною системою. Haskell і ML мають настільки повний статичний аналіз, що вони можуть потенційно опускати інформацію типу під час виконання.
Відповідь вже дана вище. Намагаємось розмежувати концепцію сильного проти тижня та статичного проти динамічного.
Сильно набрано: не буде автоматично перетворено з одного типу в інший
У Go або Python подібні сильно набрані мови "2" + 8 призведе до помилки типу, оскільки вони не дозволяють "ввести примус".
Слабо (нещільно) набрано: буде автоматично перетворено в один тип до іншого: Слабо набрані мови, такі як JavaScript або Perl, не видадуть помилки, і в цьому випадку JavaScript призведе до "28", а perl - 10.
Приклад Perl:
my $a = "2" + 8;
print $a,"\n";
Збережіть його в main.pl і запустіть, perl main.pl
і ви отримаєте вихід 10.
У програмуванні програміст визначає статичне введення та динамічне введення відносно точки, в якій перевіряються типи змінних. Статичними мовами набору тексту є ті, у яких перевірка типів проводиться під час компіляції, тоді як динамічні набрані мови - це ті, у яких перевірка типів виконується під час виконання.
Що це означає?
У програмі 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
Одне не означає іншого. Для статичного введення мови це означає, що типи всіх змінних відомі або виводяться під час компіляції.
Сильно збірний язик не дозволяє використовувати один тип , як інший. C є слабо типізованою мовою і є хорошим прикладом того, що сильно набрані мови не дозволяють. В C ви можете передати елемент даних неправильного типу, і він не скаржиться. Сильно набраними мовами ви не можете.
Сильне введення тексту, ймовірно, означає, що змінні мають чітко визначений тип і що існують суворі правила щодо поєднання змінних різних типів у виразах. Наприклад, якщо A є цілим числом, а B - поплавком, то суворим правилом щодо A + B може бути те, що A передається до поплавця, а результат повертається як поплавок. Якщо A - ціле число, а B - рядок, то суворим правилом може бути те, що A + B недійсне.
Статична типізація, ймовірно, означає, що типи призначаються під час компіляції (або її еквівалент для некомпільованих мов) і не можуть змінюватися під час виконання програми.
Зауважте, що ці класифікації не є взаємовиключними, бо я б очікував, що вони часто трапляються разом. Багато сильно типізованих мов також набираються статично.
І зауважте, що коли я вживаю слово "напевно", це тому, що не існує загальновизнаних визначень цих термінів. Як ви вже бачили з відповідей поки що.