Що означає "безпечний для типу"?
Що означає "безпечний для типу"?
Відповіді:
Безпека типу означає, що компілятор перевірятиме типи під час компіляції та видасть помилку, якщо ви спробуєте призначити неправильний тип змінній.
Деякі прості приклади:
// Fails, Trying to put an integer in a string
String one = 1;
// Also fails.
int foo = "bar";
Це стосується також аргументів методу, оскільки ви передаєте їм явні типи:
int AddTwoNumbers(int a, int b)
{
return a + b;
}
Якщо я спробував зателефонувати, використовуючи:
int Sum = AddTwoNumbers(5, "5");
Компілятор видасть помилку, тому що я передаю рядок ("5"), і він очікує ціле число.
На мові, що не вводиться, як-от JavaScript, я можу зробити наступне:
function AddTwoNumbers(a, b)
{
return a + b;
}
якщо я називаю це так:
Sum = AddTwoNumbers(5, "5");
Javascript автоматично перетворює 5 в рядок і повертає "55". Це пов’язано з JavaScript за допомогою знака + для об'єднання рядків. Для того, щоб це було відомо про тип, вам потрібно зробити щось на кшталт:
function AddTwoNumbers(a, b)
{
return Number(a) + Number(b);
}
Або, можливо:
function AddOnlyTwoNumbers(a, b)
{
if (isNaN(a) || isNaN(b))
return false;
return Number(a) + Number(b);
}
якщо я називаю це так:
Sum = AddTwoNumbers(5, " dogs");
Javascript автоматично перетворює 5 в рядок і додає їх, щоб повернути "5 собак".
Не всі динамічні мови настільки ж прощають, як JavaScript (насправді динамічна мова не означає, що мова йде про вільну мову (див. Python)).
Незважаючи на те, що це зручно, він відкриває вам безліч помилок, які можна легко пропустити і виявити лише тестуючи запущену програму. Особисто я вважаю за краще, щоб мій компілятор сказав мені, чи допустив я цю помилку.
Тепер повернемося до C # ...
C # підтримує мовну функцію під назвою коваріація , це в основному означає, що ви можете замінити базовий тип на дочірній тип і не викликати помилок, наприклад:
public class Foo : Bar
{
}
Тут я створив новий клас (Foo), що підкласи Bar. Тепер я можу створити метод:
void DoSomething(Bar myBar)
І зателефонуйте, використовуючи як Foo, або Bar як аргумент, і те, і інше буде працювати, не викликаючи помилки. Це працює, тому що C # знає, що будь-який дочірній клас Bar буде реалізовувати інтерфейс Bar.
Однак ви не можете зробити зворотне:
void DoSomething(Foo myFoo)
У цій ситуації я не можу передати Bar до цього методу, оскільки компілятор не знає, що Bar реалізує інтерфейс Foo. Це тому, що дочірній клас може (і зазвичай буде) сильно відрізнятися від батьківського класу.
Звичайно, зараз я пішов із глибокого кінця і вийшов за рамки оригінального питання, але його всі хороші речі знати :)
Безпеку типу не слід змішувати зі статичним / динамічним набором тексту або сильним / слабким набором тексту.
Мова, безпечна для типу, - це лише те, що єдині операції, які можна виконати над даними, - це ті, які підтверджуються типом даних. Тобто, якщо ваші дані мають тип X
і X
не підтримують операцію y
, мова не дозволить виконати y(X)
.
Це визначення не встановлює правила, коли це встановлено. Це може бути під час компіляції (статичне введення тексту) або під час виконання (динамічне введення тексту), як правило, через винятки. Це може бути і те і інше: деякі статично набрані мови дозволяють передавати дані з одного типу в інший, а дійсність кастів потрібно перевіряти під час виконання (уявіть, що ви намагаєтеся передати " Object
a" Consumer
- у компілятора немає спосіб дізнатися, прийнятний він чи ні).
Безпека типу не обов'язково означає сильно набраний текст - деякі мови, як відомо, слабо набрані, але все-таки, певно, є безпечними. Візьмемо, наприклад, Javascript: його система типів настільки ж слабка, як і раніше, але все-таки суворо визначена. Це дозволяє автоматично вводити дані (скажімо, рядки в ints), але в межах чітко визначених правил. Наскільки мені відомо, жоден випадок, коли програма Javascript буде вести себе не визначено, і якщо ви досить розумні (я не є), ви повинні мати можливість передбачити, що станеться під час читання коду Javascript.
Прикладом небезпечної для мови мови програмування є C: читання / запис значення масиву поза межами масиву має невизначене поведінку за специфікацією . Неможливо передбачити, що станеться. C - мова, яка має систему типів, але не є безпечною для типу.
Безпека типу - це не просто обмеження часу компіляції, а обмеження часу виконання . Я відчуваю, що навіть через весь цей час ми можемо додати додаткової ясності цьому.
Є 2 основні питання, пов'язані з безпекою типу. Пам'ять ** та тип даних (з відповідними операціями).
char
, Як правило , потрібно 1 байт на символ, або 8 біт ( в залежності від мови, Java і C # магазину Юникода символів , які вимагають 16 біт). Потрібно int
4 байти або 32 біта (як правило).
Візуально:
char: |-|-|-|-|-|-|-|-|
int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
Безпечна мова типу не дозволяє вставляти int в char під час виконання (це повинно викинути вигляд виключення класу або виключення з пам'яті). Однак, в небезпечній мові типу, ви перезаписали б наявні дані в 3 сусідні байти пам'яті.
int >> char:
|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|
У вищенаведеному випадку 3 байти праворуч перезаписуються, тому будь-які вказівники на цю пам’ять (скажімо, 3 послідовних символи), які очікують отримати передбачуване значення char, тепер матимуть сміття. Це спричиняє undefined
поведінку у вашій програмі (або ще гірше, можливо, в інших програмах залежно від того, як ОС розподіляє пам'ять - дуже малоймовірно в ці дні).
** Хоча цей перший випуск технічно не стосується типу даних, введіть безпечні мови вирішуйте його по суті, і він візуально описує проблему тим, хто не знає, як виглядає розподіл пам'яті.
Більш тонка і пряма проблема полягає в тому, коли два типи даних використовують однакове розподілення пам'яті. Візьміть int vs unsigned int. Обидва - 32 біти. (Так само легко можуть бути знаки [4] та int, але більш поширеною проблемою є uint vs. int).
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
Небезпечна мова типу дозволяє програмісту посилатись на правильно виділений проміжок у 32 біти, але коли значення неподписаного int зчитується у просторі int (або навпаки), ми знову маємо undefined
поведінку. Уявіть проблеми, які це може спричинити в банківській програмі:
"Чувак! Я завищив $ 30, і тепер у мене залишилося $ 65 506 !!"
..., звичайно, банківські програми використовують значно більші типи даних. ;) ЛОЛ!
Як вже вказували інші, наступний випуск - обчислювальні операції на типи. Це вже було достатньо висвітлено.
Більшість програмістів сьогодні ніколи не потребують таких проблем, якщо вони не використовують щось на зразок C або C ++. Обидві ці мови дозволяють програмістам легко порушувати безпеку типу під час запуску (пряме посилання на пам'ять), незважаючи на максимум зусиль компіляторів, щоб мінімізувати ризик. ЯКЩО це не все погано.
Однією з причин цих мов є настільки обчислювально швидкий факт, що вони не обтяжуються, перевіряючи сумісність типів під час операцій, як, наприклад, Java. Вони припускають, що розробник - це хороша раціональна істота, яка не додаватиме рядок і int разом, і для цього розробник винагороджується швидкістю / ефективністю.
Багато відповідей тут пов'язують безпеку типу зі статичним набором та динамічним набором тексту. Динамічно набрана мова (як, наприклад, smalltalk) також може бути безпечною для типу.
Коротка відповідь: мова вважається безпечною для типу, якщо жодна операція не призводить до невизначеної поведінки. Багато хто вважає вимогу конверсій явного типу, необхідних для мови, строго вводити, оскільки автоматичні перетворення іноді можуть призводити до чітко визначеної, але несподіваної / неінтуїтивної поведінки.
if no operation leads to undefined behavior
.
Пояснення спеціаліста з ліберальних мистецтв, а не спеціалістів з спеціальностей:
Коли люди кажуть, що мова чи мовна функція є безпечними для типу, вони означають, що мова допоможе вам запобігти, наприклад, передавати щось, що не є цілим числом, до певної логіки, яка очікує ціле число.
Наприклад, у C # я визначаю функцію як:
void foo(int arg)
Потім компілятор зупинить мене від цього:
// call foo
foo("hello world")
В інших мовах компілятор не зупинить мене (або немає компілятора ...), тому рядок буде переданий логіці і тоді, мабуть, трапиться щось погане.
Введіть безпечні мови, намагайтеся зловити більше за "час компіляції".
З нижньої сторони, із типом безпечних мов, коли у вас є рядок типу "123" і ви хочете оперувати нею як int, ви повинні написати більше коду для перетворення рядка в int або коли у вас є int як 123, і хочете використовувати його в повідомленні типу "Відповідь 123", вам потрібно написати більше коду для перетворення / передачі його в рядок.
Для кращого розуміння дивіться відео нижче, яке демонструє код на безпечній мові (C #), а НЕ вводить безпечну мову (javascript).
http://www.youtube.com/watch?v=Rlw_njQhkxw
Тепер довгий текст.
Тип безпеки означає запобігання помилок типу. Помилка типу виникає, коли тип даних одного типу присвоюється іншому типу НЕЗАКОННО, і ми отримуємо небажані результати.
Наприклад, JavaScript не є безпечною мовою типу. У наведеному нижче коді “num” - числова змінна, а “str” - рядок. Javascript дозволяє мені робити «num + str», тепер GUESS буде робити це арифметикою чи конкатенацією.
Тепер для наведеного нижче коду результати "55", але важливим моментом є створення плутанини, яку операцію він буде робити.
Це відбувається тому, що javascript не є безпечною мовою. Це дозволяє встановлювати один тип даних на інший тип без обмежень.
<script>
var num = 5; // numeric
var str = "5"; // string
var z = num + str; // arthimetic or concat ????
alert(z); // displays “55”
</script>
C # - безпечна мова типу. Це не дозволяє призначити один тип даних іншому типу даних. Наведений нижче код не дозволяє оператору "+" для різних типів даних.
Безпечний тип означає, що програмно тип даних для змінної, повернутого значення або аргументу повинен відповідати певним критеріям.
На практиці це означає, що 7 (цілий тип) відрізняється від "7" (цитований символ рядкового типу).
PHP, Javascript та інші мови динамічного сценарію зазвичай слабо набрані, тому що вони спробують перетворити (рядок) "7" в (ціле число) 7, якщо ви спробуєте додати "7" + 3, хоча іноді доводиться це робити явно (а Javascript використовує символ "+" для конкатенації).
C / C ++ / Java цього не зрозуміє, або замість результату замінить "73". Безпека типу запобігає таким типам помилок у коді, роблячи явну вимогу типу.
Безпека типу дуже корисна. Рішенням вищезгаданих "7" + 3 було б введення cast (int) "7" + 3 (дорівнює 10).
Концепція:
Щоб бути дуже простим Type Safe, як значення, він гарантує, що тип змінної повинен бути безпечним
тому мова йде про безпеку типів вашого сховища з точки зору змінних.
Спробуйте це пояснення на ...
TypeSafe означає, що змінні під час компіляції статично перевіряються на відповідне призначення. Наприклад, скопіюйте рядок або ціле число. Ці два типи даних не можуть бути присвоєні між собою (тобто ви не можете призначити ціле число рядку, а також не можете призначити рядок цілому числу).
Для поведінки, що не стосується типу, врахуйте це:
object x = 89;
int y;
якщо ви намагаєтесь це зробити:
y = x;
компілятор видає помилку, яка говорить, що він не може перетворити System.Object в цілий число. Це потрібно робити явно. Один із способів:
y = Convert.ToInt32( x );
Наведене вище завдання не є безпечним. Типове безпечне призначення - це типи, які можуть бути безпосередньо призначені один одному.
Колекції, що не містять типів, містять багато ASP.NET (наприклад, колекції програм, сеансів та перегляду держав). Хороша новина про ці колекції полягає в тому, що (зведення до мінімуму декількох міркувань щодо управління станом сервера) ви можете розмістити майже будь-який тип даних у будь-якій з трьох колекцій. Погана новина: оскільки ці колекції не є безпечними для друку, вам потрібно буде належним чином передати ці значення, коли ви їх отримаєте назад.
Наприклад:
Session[ "x" ] = 34;
працює чудово. Але щоб призначити ціле значення назад, вам потрібно буде:
int i = Convert.ToInt32( Session[ "x" ] );
Прочитайте інформацію про дженерики щодо способів, які допоможуть вам легко реалізовувати колекції typesafe.
C # - безпечна мова, але слідкуйте за статтями про C # 4.0; цікаві динамічні можливості ткацького верстата (чи добре, що C # по суті отримує Option Strict: Off ... ми побачимо).
Type-Safe - код, який отримує доступ лише до пам'яті, до якої він має право доступу, і лише чітко визначеними, допустимими способами. Код, захищений типом, не може виконувати операцію над об'єктом, недійсним для цього об'єкта. Компілятори мови C # і VB.NET завжди створюють безпечний для типу код, який підтверджується безпечним для типу під час компіляції JIT.
Безпечний тип означає, що набір значень, які можуть бути присвоєні програмній змінній, повинен відповідати чітко визначеним і перевіреним критеріям. Типові безпечні змінні призводять до більш надійних програм, оскільки алгоритми, що управляють змінними, можуть довіряти, що змінна прийме лише одне з чітко визначеного набору значень. Дотримання цієї довіри забезпечує цілісність та якість даних та програми.
Для багатьох змінних набір значень, які можуть бути присвоєні змінній, визначається під час написання програми. Наприклад, змінній під назвою "колір" може бути дозволено приймати значення "червоний", "зелений" або "синій" і ніколи будь-які інші значення. Для інших змінних ці критерії можуть змінюватися під час виконання. Наприклад, змінній під назвою "колір" може бути дозволено приймати значення лише у стовпці "ім'я" таблиці "Кольори" у реляційній базі даних, де "червоний," зелений "та" синій "- це три значення для "name" в таблиці "Colors", але деякі інші частини комп'ютерної програми можуть бути в змозі додати до цього списку під час роботи програми, а змінна може приймати нові значення після їх додавання до таблиці Colors. .
Багато мов, що захищають тип, створюють ілюзію "безпека типу", наполягаючи на чіткому визначенні типів змінних і лише дозволяючи присвоювати змінній значення одного і того ж "типу". Є кілька проблем з таким підходом. Наприклад, програма може мати змінну "yearOfBirth" - це рік народження людини, і це спокушає вводити це як коротке ціле число. Однак це не коротке ціле число. Цього року це кількість, менша за 2009 рік та більша за -10000. Однак цей набір зростає на 1 щороку, коли програма працює. Зробити це "коротким int" не є адекватним. Для забезпечення безпеки цієї змінної типу потрібна функція перевірки часу виконання, яка гарантує, що кількість завжди перевищує -10000 і менше, ніж наступного календарного року.
Мови, які використовують динамічне введення (або набирання качок, або маніфестне введення), такі як Perl, Python, Ruby, SQLite та Lua, не мають поняття введених змінних. Це змушує програміста написати процедуру перевірки часу виконання для кожної змінної, щоб переконатися, що вона правильна, або перенести наслідки незрозумілих винятків під час виконання. З мого досвіду, програмісти на мовах статичного типу, такі як C, C ++, Java та C #, часто переймаються думкою, що статично визначені типи - це все, що потрібно зробити, щоб отримати переваги безпеки типу. Для багатьох корисних комп'ютерних програм це просто не відповідає дійсності, і важко передбачити, чи це правда для будь-якої конкретної комп'ютерної програми.
Довгий і короткий .... Ви хочете захистити тип? Якщо так, то запишіть функції часу виконання, щоб переконатися, що коли змінній присвоєно значення, вона відповідає чітко визначеним критеріям. Недоліком є те, що це робить аналіз домену справді важким для більшості комп'ютерних програм, оскільки вам потрібно чітко визначити критерії для кожної змінної програми.