Что означает «безопасный тип»?
Что означает «безопасный тип»?
Ответы:
Безопасность типов означает, что компилятор будет проверять типы во время компиляции и выдаст ошибку, если вы попытаетесь присвоить переменной неверный тип.
Несколько простых примеров:
// 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: его система типов так же слаба, как и они, но все же строго определена. Это позволяет автоматически приводить данные (скажем, строки в целые числа), но в рамках четко определенных правил. Насколько мне известно, ни один случай, когда программа Javascript будет вести себя неопределенным образом, и если вы достаточно умны (я не), вы должны быть в состоянии предсказать, что произойдет при чтении кода Javascript.
Примером небезопасного языка программирования является C: чтение / запись значения массива вне границ массива имеет неопределенное поведение по спецификации . Невозможно предсказать, что произойдет. C - это язык, который имеет систему типов, но не является безопасным для типов.
Безопасность типов - это не только ограничение времени компиляции, но и ограничение времени выполнения . Я чувствую, что даже после всего этого времени мы можем внести дополнительную ясность в это.
Есть 2 основных вопроса, связанных с безопасностью типов. Память ** и тип данных (с соответствующими операциями).
char
Обычно A требует 1 байт на символ или 8 бит (зависит от языка, в Java и C # хранятся символы Unicode, для которых требуется 16 бит). int
Требуется 4 байта, или 32 бита (обычно).
Визуально:
char: |-|-|-|-|-|-|-|-|
int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
Безопасный по типу язык не позволяет вставлять int в char во время выполнения (это должно привести к исключению типа из класса или из памяти). Однако на небезопасном языке типа вы перезаписываете существующие данные еще на 3 смежных байта памяти.
int >> char:
|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|
В приведенном выше случае 3 байта справа перезаписываются, поэтому любые указатели на эту память (скажем, 3 последовательных символа), которые ожидают получить предсказуемое значение символа, теперь будут иметь мусор. Это вызываетundefined
поведение в вашей программе (или, что еще хуже, возможно, в других программах, в зависимости от того, как ОС выделяет память - очень маловероятно в наши дни).
** Хотя эта первая проблема технически не относится к типу данных, языки с безопасными типами обращаются к ней по своей сути, и она визуально описывает проблему для тех, кто не знает, как «выглядит» выделение памяти.
Более тонкий и прямой тип проблемы заключается в том, что два типа данных используют одинаковое распределение памяти. Возьмите int против неподписанного int. Оба 32 бит. (Точно так же легко могут быть char [4] и int, но более распространенной проблемой является uint vs. int).
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
Небезопасный язык типов позволяет программисту ссылаться на правильно распределенный интервал из 32 битов, но когда значение беззнакового целого читается в пространстве целого (или наоборот), мы снова имеем undefined
поведение. Представьте себе проблемы, которые это может вызвать в банковской программе:
"Чувак! Я переиграл 30 долларов, и теперь у меня осталось 65 506 долларов !!"
... Конечно, банковские программы используют гораздо большие типы данных. ;) РЖУНИМАГУ!
Как уже отмечали другие, следующая проблема - вычислительные операции над типами. Это уже достаточно покрыто.
Большинству программистов сегодня не нужно беспокоиться о таких вещах, если они не используют что-то вроде C или C ++. Оба этих языка позволяют программистам легко нарушать безопасность типов во время выполнения (прямое обращение к памяти), несмотря на все усилия компиляторов минимизировать риск. ОДНАКО, это не все плохо.
Одна из причин, по которой эти языки настолько быстры в вычислительном отношении, заключается в том, что они не обременены проверкой совместимости типов во время операций во время выполнения, таких как, например, Java. Они предполагают, что разработчик - хорошее рациональное существо, которое не будет добавлять строку и целое число вместе, и за это разработчик вознагражден скоростью / эффективностью.
Многие ответы здесь связывают безопасность типов со статической и динамической типизацией. Динамически типизированный язык (например, 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 в Integer. Вы должны сделать это явно. Одним из способов будет:
y = Convert.ToInt32( x );
Приведенное выше задание не является безопасным. Назначение типов безопасности - это когда типы могут быть непосредственно назначены друг другу.
В ASP.NET имеется множество небезопасных коллекций (например, коллекции приложения, сеанса и представления состояния). Хорошая новость об этих коллекциях заключается в том, что (сводя к минимуму несколько факторов управления состоянием сервера) вы можете поместить практически любой тип данных в любую из трех коллекций. Плохая новость: поскольку эти коллекции не являются типобезопасными, вам нужно будет соответствующим образом привести значения при извлечении их обратно.
Например:
Session[ "x" ] = 34;
работает отлично. Но чтобы вернуть целочисленное значение обратно, вам необходимо:
int i = Convert.ToInt32( Session[ "x" ] );
Читайте о дженериках, чтобы узнать, как это средство поможет вам легко создавать безопасные коллекции.
C # - это безопасный язык, но следите за статьями о C # 4.0; вырисовываются интересные динамические возможности (хорошо ли, что C # по сути получает Option Strict: Off ... посмотрим).
Безопасный тип - это код, который обращается только к тем ячейкам памяти, к которым он имеет доступ, и только четко определенными, допустимыми способами. Типобезопасный код не может выполнить операцию с объектом, который недопустим для этого объекта. Компиляторы языка C # и VB.NET всегда генерируют код, безопасный для типов, который проверяется на то, что он является безопасным во время компиляции JIT.
Безопасный тип означает, что набор значений, которые могут быть назначены программной переменной, должен соответствовать четко определенным и проверяемым критериям. Безопасные по типу переменные приводят к созданию более надежных программ, поскольку алгоритмы, управляющие переменными, могут полагать, что переменная будет принимать только одно из четко определенного набора значений. Сохранение этого доверия обеспечивает целостность и качество данных и программы.
Для многих переменных набор значений, которые могут быть назначены переменной, определяется во время написания программы. Например, переменной с именем «color» может быть разрешено принимать значения «red», «green» или «blue» и никогда не иметь никаких других значений. Для других переменных эти критерии могут изменяться во время выполнения. Например, переменная с именем «color» может принимать значения только в столбце «name» таблицы «Colors» в реляционной базе данных, где «red», «green» и «blue» - это три значения для «имени» в таблице «Цвета», но некоторая другая часть компьютерной программы может быть в состоянии добавить в этот список во время работы программы, и переменная может принять новые значения после того, как они добавлены в таблицу Цветов ,
Многие безопасные от типов языки создают иллюзию «безопасности типов», настаивая на строгом определении типов для переменных и позволяя переменной назначать только значения одного и того же «типа». Есть несколько проблем с этим подходом. Например, программа может иметь переменную yearOfBirth, которая представляет собой год рождения человека, и заманчиво привести его к типу короткого целого числа. Однако это не короткое целое число. В этом году это число меньше 2009 года и больше -10000. Тем не менее, этот набор увеличивается на 1 каждый год по мере выполнения программы. Делать это "коротким целым" недостаточно. Чтобы сделать эту переменную безопасной для типов, необходима функция проверки во время выполнения, которая гарантирует, что число всегда будет больше -10000 и меньше, чем в следующем календарном году.
Языки, которые используют динамическую типизацию (или типизацию утилит, или манифестную типизацию), такие как Perl, Python, Ruby, SQLite и Lua, не имеют понятия типизированных переменных. Это вынуждает программиста написать подпрограмму проверки времени выполнения для каждой переменной, чтобы гарантировать ее правильность или выдержать последствия необъяснимых исключений времени выполнения. По моему опыту, программисты на статически типизированных языках, таких как C, C ++, Java и C #, часто склоняются к мысли, что статически определенные типы - это все, что им нужно сделать, чтобы получить преимущества безопасности типов. Это просто неверно для многих полезных компьютерных программ, и трудно предсказать, верно ли это для какой-либо конкретной компьютерной программы.
Длинный и короткий .... Вы хотите безопасность типов? Если это так, то напишите функции времени выполнения, чтобы гарантировать, что когда переменной присваивается значение, она соответствует четко определенным критериям. Недостатком является то, что это делает анализ предметной области действительно трудным для большинства компьютерных программ, потому что вы должны явно определить критерии для каждой программной переменной.