¿Qué es el tipo seguro?

Respuestas:

247

La seguridad de tipo significa que el compilador validará los tipos durante la compilación y arrojará un error si intenta asignar el tipo incorrecto a una variable.

Algunos ejemplos simples:

// Fails, Trying to put an integer in a string
String one = 1;
// Also fails.
int foo = "bar";

Esto también se aplica a los argumentos del método, ya que les está pasando tipos explícitos:

int AddTwoNumbers(int a, int b)
{
    return a + b;
}

Si intenté llamar a eso usando:

int Sum = AddTwoNumbers(5, "5");

El compilador arrojaría un error, porque estoy pasando una cadena ("5") y espera un número entero.

En un lenguaje mecanografiado libremente, como javascript, puedo hacer lo siguiente:

function AddTwoNumbers(a, b)
{
    return a + b;
}

si lo llamo así:

Sum = AddTwoNumbers(5, "5");

Javascript convierte automáticamente el 5 en una cadena y devuelve "55". Esto se debe a que JavaScript usa el signo + para la concatenación de cadenas. Para que sea compatible con la escritura, necesitaría hacer algo como:

function AddTwoNumbers(a, b)
{
    return Number(a) + Number(b);
}

O, posiblemente:

function AddOnlyTwoNumbers(a, b)
{
    if (isNaN(a) || isNaN(b))
        return false;
    return Number(a) + Number(b);
}

si lo llamo así:

Sum = AddTwoNumbers(5, " dogs");

Javascript convierte automáticamente el 5 en una cadena y los agrega para devolver "5 perros".

No todos los lenguajes dinámicos son tan indulgentes como javascript (de hecho, un lenguaje dinámico no implica implícitamente un lenguaje tipeado suelto (vea Python)), algunos de ellos le darán un error de tiempo de ejecución en la conversión de tipos no válidos.

Si bien es conveniente, te abre a una gran cantidad de errores que pueden pasarse por alto fácilmente y que solo pueden identificarse al probar el programa en ejecución. Personalmente, prefiero que mi compilador me diga si cometí ese error.

Ahora, volviendo a C # ...

C # admite una función de lenguaje llamada covarianza , esto básicamente significa que puede sustituir un tipo base por un tipo secundario y no causar un error, por ejemplo:

 public class Foo : Bar
 {
 }

Aquí, creé una nueva clase (Foo) que subclasifica Bar. Ahora puedo crear un método:

 void DoSomething(Bar myBar)

Y llámelo usando un Foo o un Bar como argumento, ambos funcionarán sin causar un error. Esto funciona porque C # sabe que cualquier clase secundaria de Bar implementará la interfaz de Bar.

Sin embargo, no puedes hacer lo inverso:

void DoSomething(Foo myFoo)

En esta situación, no puedo pasar Bar a este método, porque el compilador no sabe que Bar implementa la interfaz de Foo. Esto se debe a que una clase secundaria puede (y generalmente será) muy diferente a la clase principal.

Por supuesto, ahora me he alejado del fondo y más allá del alcance de la pregunta original, pero todo es bueno saberlo :)

FlySwat
fuente
26
Creo que esta respuesta es incorrecta: la seguridad de escritura no se aplica necesariamente en el momento de la compilación. Entiendo que Scheme, por ejemplo, se considera de tipo seguro, pero se verifica dinámicamente (la seguridad de tipo se aplica en tiempo de ejecución). Esto parafrasea principalmente la introducción a Tipos y lenguajes de programación, por Benjamin C. Pierce.
Nicolas Rinaudo
11
Lo que usted describe se llama polimorfismo, no covarianza. La covarianza se usa en genéricos.
IllidanS4 quiere que Mónica regrese el
@NicolasRinaudo tenga en cuenta que la brecha entre los lenguajes dinámicos y los estáticos está siendo erosionada por la compilación dinámica y la precompilación para los idiomas "interpretados", y por la reflexión en los lenguajes "compilados". Reflection permite escribir en tiempo de ejecución, por ejemplo, un lenguaje compilado puede decir "oye, esto tiene un método Quack (), lo llamaré y veré qué sucede". Los lenguajes similares a Pascal también suelen tener una verificación de desbordamiento del tiempo de ejecución (opcional), lo que lleva a que los errores del "compilador" que ocurren en el tiempo de ejecución "no puedan caber enteros suministrados en el destino de 8 bits {core dump}".
Code Abominator
2
Su ejemplo hace referencia a un concepto llamado "fuertemente tipado" que no es lo mismo que tipo seguridad. La seguridad de tipos es cuando un lenguaje puede detectar errores de tipo en la ejecución o en el tiempo de compilación. Python, por ejemplo, está tipeado débilmente y es seguro. Esta respuesta debe marcarse ya que es muy engañosa.
dantebarba
. explicación en v en general buena, pero la seguridad de tipos no es el mismo que con establecimiento inflexible
senseiwu
57

La seguridad de escritura no debe confundirse con la escritura estática / dinámica o la escritura fuerte / débil.

Un lenguaje de tipo seguro es aquel en el que las únicas operaciones que se pueden ejecutar en los datos son aquellas que son toleradas por el tipo de datos. Es decir, si sus datos son de tipo Xy Xno admiten la operación y, entonces el idioma no le permitirá ejecutar y(X).

Esta definición no establece reglas cuando se marca esto. Puede ser en tiempo de compilación (escritura estática) o en tiempo de ejecución (escritura dinámica), generalmente a través de excepciones. Puede ser un poco de ambos: algunos lenguajes de tipo estático le permiten transmitir datos de un tipo a otro, y la validez de los lanzamientos debe verificarse en tiempo de ejecución (imagine que está tratando de enviar un Objecta un Consumer- el compilador no tiene forma de saber si es aceptable o no).

La seguridad de tipo no significa necesariamente que esté fuertemente tipeado, ya que algunos idiomas son muy débiles, pero aún se puede decir que son seguros. Tomemos Javascript, por ejemplo: su sistema de tipos es tan débil como parece, pero todavía está estrictamente definido. Permite la transmisión automática de datos (por ejemplo, cadenas a ints), pero dentro de reglas bien definidas. No tengo conocimiento de ningún caso en el que un programa Javascript se comporte de forma indefinida, y si eres lo suficientemente inteligente (no lo soy), deberías poder predecir qué sucederá al leer el código Javascript.

Un ejemplo de lenguaje de programación de tipo inseguro es C: leer / escribir un valor de matriz fuera de los límites de la matriz tiene un comportamiento indefinido por especificación . Es imposible predecir lo que sucederá. C es un lenguaje que tiene un sistema de tipos, pero no es seguro.

Nicolas Rinaudo
fuente
1
¿Cuáles son otros ejemplos de lenguajes de tipo inseguro? ¿Qué quiere decir con "escribir un valor de matriz fuera de los límites de la matriz tiene un comportamiento indefinido por especificación. Es imposible predecir lo que sucederá". Al igual que Javascript, volverá indefinido ¿verdad? O realmente puede pasar cualquier cosa. ¿Puedes dar ejemplo de esto?
ARCA
1
@AkshayrajKore seguro. Las matrices son punteros de memoria, por lo que al escribir fuera de los límites, puede sobrescribir los datos de otro programa, que no pueden hacer nada, bloquear el programa, hacer que borre su disco duro, no está definido y depende de quién está leyendo ese bit de memoria y cómo reaccionará a eso.
Nicolas Rinaudo
@Nicolas Rinaudo Eso no es correcto. Deberías leer sobre la memoria virtual. Cada proceso tiene su propio espacio de dirección virtual, por lo que un proceso no puede "sobrescribir los datos de otro programa" de esa manera.
ilstam
Estás en lo correcto, esto debería haber leído que podrías estar sobrescribiendo otra parte de la memoria de tu programa, incluido, creo, el programa en sí.
Nicolas Rinaudo
@NicolasRinaudo El segmento de código del programa se asigna de solo lectura en el espacio de direcciones virtuales. Entonces, si trataste de escribirle, eso causaría una falla de segmentación y tu programa se bloquearía. Además, si intentas escribir en la memoria no asignada, eso provocará un error de página y se bloqueará nuevamente. Sin embargo, si no tiene suerte, puede sobrescribir los datos de la pila o el montón del proceso (como otras variables u otras cosas). En ese caso, probablemente no se estrellaría de inmediato, lo que es aún peor porque no notará el error hasta (con suerte) más tarde.
ilstam
32

La seguridad de tipos no es solo una restricción de tiempo de compilación, sino una restricción de tiempo de ejecución . Siento que incluso después de todo este tiempo, podemos agregar más claridad a esto.

Hay 2 problemas principales relacionados con la seguridad de tipos. Memoria ** y tipo de datos (con sus operaciones correspondientes).

Memoria**

A charnormalmente requiere 1 byte por carácter u 8 bits (depende del lenguaje, Java y C # almacena caracteres unicode que requieren 16 bits). Un intrequiere 4 bytes, o 32 bits (generalmente).

Visualmente:

char: |-|-|-|-|-|-|-|-|

int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

Un lenguaje de tipo seguro no permite que se inserte un int en un char en tiempo de ejecución (esto debería generar algún tipo de conversión de clase o excepción de memoria insuficiente). Sin embargo, en un lenguaje de tipo inseguro, sobrescribiría los datos existentes en 3 bytes adyacentes más de memoria.

int >> char:

|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|

En el caso anterior, los 3 bytes a la derecha se sobrescriben, por lo que cualquier puntero a esa memoria (digamos 3 caracteres consecutivos) que esperan obtener un valor de char predecible ahora tendrá basura. Esto provoca un undefinedcomportamiento en su programa (o peor, posiblemente en otros programas dependiendo de cómo el sistema operativo asigna memoria, muy poco probable en estos días).

** Si bien este primer problema no es técnicamente sobre el tipo de datos, los idiomas seguros de tipo lo abordan de manera inherente y describe visualmente el problema a aquellos que no saben cómo "se ve" la asignación de memoria.

Tipo de datos

El problema de tipo más sutil y directo es cuando dos tipos de datos usan la misma asignación de memoria. Tome un int vs un unsigned int. Ambos son de 32 bits. (Con la misma facilidad podría ser un char [4] y un int, pero el problema más común es uint vs. int).

|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

Un lenguaje de tipo inseguro permite al programador hacer referencia a un intervalo de 32 bits correctamente asignado, pero cuando el valor de un int sin signo se lee en el espacio de un int (o viceversa), nuevamente tenemos undefinedcomportamiento. Imagine los problemas que esto podría causar en un programa bancario:

"¡Amigo! ¡Sobregiré $ 30 y ahora me quedan $ 65,506!"

... por supuesto, los programas bancarios utilizan tipos de datos mucho más grandes. ;) LOL!

Como otros ya han señalado, el siguiente problema son las operaciones computacionales en los tipos. Eso ya ha sido suficientemente cubierto.

Velocidad vs seguridad

La mayoría de los programadores de hoy nunca necesitan preocuparse por tales cosas a menos que estén usando algo como C o C ++. Ambos lenguajes permiten a los programadores violar fácilmente la seguridad de tipos en tiempo de ejecución (referencia directa de memoria) a pesar de los mejores esfuerzos de los compiladores para minimizar el riesgo. SIN EMBARGO, esto no es todo malo.

Una de las razones por las que estos lenguajes son tan rápidos desde el punto de vista computacional es que no se cargan al verificar la compatibilidad de tipos durante operaciones de tiempo de ejecución como, por ejemplo, Java. Asumen que el desarrollador es un buen ser racional que no agregará una cadena y un int juntos y por eso, el desarrollador es recompensado con velocidad / eficiencia.

Gr3go
fuente
27

Muchas respuestas aquí combinan seguridad de tipos con escritura estática y escritura dinámica. Un lenguaje escrito dinámicamente (como smalltalk) también puede ser de tipo seguro.

Una respuesta corta: un lenguaje se considera seguro de tipo si ninguna operación conduce a un comportamiento indefinido. Muchos consideran el requisito de conversiones de tipo explícito necesarias para que un idioma se escriba estrictamente , ya que las conversiones automáticas a veces pueden conducir a comportamientos bien definidos pero inesperados / poco intuitivos.

ididak
fuente
1
Espera, su definición de tipo de seguridad no tiene una sola palabra "type": D if no operation leads to undefined behavior.
VasiliNovikov
1
Además, no estaría de acuerdo con tal definición. Creo que la seguridad de tipos significa exactamente 1. la existencia de tipos 2. el conocimiento de ellos para el compilador, y las verificaciones apropiadas, por supuesto.
VasiliNovikov
10

Un lenguaje de programación que es 'seguro de tipo' significa lo siguiente:

  1. No puede leer de variables no inicializadas
  2. No puede indexar matrices más allá de sus límites
  3. No puede realizar lanzamientos de tipo sin marcar
Kekule
fuente
8

Una explicación de una especialización en artes liberales, no una especialización en ciencias básicas:

Cuando las personas dicen que un idioma o una función de idioma es segura, significan que el idioma ayudará a evitar que, por ejemplo, pase algo que no es un entero a alguna lógica que espera un entero.

Por ejemplo, en C #, defino una función como:

 void foo(int arg)

El compilador me impedirá hacer esto:

  // call foo
  foo("hello world")

En otros idiomas, el compilador no me detendría (o no hay compilador ...), por lo que la cadena se pasaría a la lógica y probablemente sucedería algo malo.

Los idiomas seguros de tipo intentan atrapar más en "tiempo de compilación".

En el lado negativo, con los idiomas de tipo seguro, cuando tiene una cadena como "123" y desea operar en ella como un int, tiene que escribir más código para convertir la cadena en un int, o cuando tiene un int como 123 y desea usarlo en un mensaje como "La respuesta es 123", debe escribir más código para convertirlo / convertirlo en una cadena.

Corey Trager
fuente
44
El especialista en artes liberales diría una explicación :) También estás combinando la escritura estática y la escritura dinámica.
ididak
1
Artes liberales "mayores", no "principales".
Corey Trager
5

Para obtener una mejor comprensión, mire el siguiente video que muestra el código en lenguaje seguro de tipo (C #) y NO escriba lenguaje seguro (javascript).

http://www.youtube.com/watch?v=Rlw_njQhkxw

Ahora para el texto largo.

La seguridad de tipo significa evitar errores de tipo. El error de tipo se produce cuando el tipo de datos de un tipo se asigna a otro tipo sin saberlo y obtenemos resultados no deseados.

Por ejemplo, JavaScript no es un tipo de lenguaje seguro. En el siguiente código, "num" es una variable numérica y "str" ​​es una cadena. Javascript me permite hacer "num + str", ahora GUESS hará aritmética o concatenación.

Ahora, para el siguiente código, los resultados son "55", pero el punto importante es la confusión creada sobre qué tipo de operación realizará.

Esto está sucediendo porque javascript no es un lenguaje de tipo seguro. Permite establecer un tipo de datos en el otro tipo sin restricciones.

<script>
var num = 5; // numeric
var str = "5"; // string
var z = num + str; // arthimetic or concat ????
alert(z); // displays  “55”
</script>

C # es un tipo de lenguaje seguro. No permite asignar un tipo de datos a otro tipo de datos. El siguiente código no permite el operador "+" en diferentes tipos de datos.

ingrese la descripción de la imagen aquí

Shivprasad Koirala
fuente
4

Type-safe significa que programáticamente, el tipo de datos para una variable, valor de retorno o argumento debe ajustarse dentro de ciertos criterios.

En la práctica, esto significa que 7 (un tipo entero) es diferente de "7" (un carácter entrecomillado del tipo de cadena).

PHP, Javascript y otros lenguajes de secuencias de comandos dinámicos suelen tener un tipo débil, ya que convertirán un (cadena) "7" en un (entero) 7 si intenta agregar "7" + 3, aunque a veces tiene que hacer esto explícitamente (y Javascript usa el carácter "+" para la concatenación).

C / C ++ / Java no lo entenderá o concatenará el resultado en "73". La seguridad de tipo evita estos tipos de errores en el código al hacer explícito el requisito de tipo.

La seguridad de tipo es muy útil. La solución al "7" + 3 anterior sería escribir cast (int) "7" + 3 (igual a 10).

Jared Farrish
fuente
3

Concepto:

Para ser muy simple Tipo seguro como los significados, se asegura de que el tipo de la variable debe ser seguro como

  1. ningún tipo de datos incorrecto, por ejemplo, no puede guardar o inicializar una variable de tipo de cadena con entero
  2. Los índices fuera de límite no son accesibles
  3. Permitir solo la ubicación de memoria específica

Por lo tanto, se trata de la seguridad de los tipos de almacenamiento en términos de variables.

azizsagi
fuente
2

Prueba esta explicación en ...

TypeSafe significa que las variables se comprueban estáticamente para la asignación adecuada en tiempo de compilación. Por ejemplo, consder una cadena o un número entero. Estos dos tipos de datos diferentes no pueden asignarse de forma cruzada (es decir, no puede asignar un entero a una cadena ni tampoco puede asignar una cadena a un entero).

Para el comportamiento no seguro de tipografía, considere esto:

object x = 89;
int y;

si intentas hacer esto:

y = x;

el compilador arroja un error que dice que no puede convertir un System.Object a un número entero. Necesitas hacer eso explícitamente. Una forma sería:

y = Convert.ToInt32( x );

La asignación anterior no es segura. Una asignación segura de tipos es donde los tipos se pueden asignar directamente entre sí.

Las colecciones no seguras de tipografía abundan en ASP.NET (por ejemplo, las colecciones de aplicaciones, sesiones y viewstate). La buena noticia acerca de estas colecciones es que (minimizando las consideraciones de administración de estado de varios servidores) puede colocar prácticamente cualquier tipo de datos en cualquiera de las tres colecciones. La mala noticia: dado que estas colecciones no son seguras, necesitará emitir los valores de manera apropiada cuando los recupere.

Por ejemplo:

Session[ "x" ] = 34;

funciona bien. Pero para volver a asignar el valor entero, deberá:

int i = Convert.ToInt32( Session[ "x" ] );

Lea sobre los genéricos para conocer las formas en que esa instalación lo ayuda a implementar fácilmente colecciones de typesafe

C # es un lenguaje seguro, pero esté atento a los artículos sobre C # 4.0; Se vislumbran interesantes posibilidades dinámicas (es bueno que C # esencialmente esté obteniendo Option Strict: Off ... ya veremos).

rp.
fuente
Personalmente, odio la conversión. A la notación, ¿por qué no usas el yeso seguro? Es solo menos llamada de función en la pila de llamadas también.
FlySwat
2

Type-Safe es un código que accede solo a las ubicaciones de memoria a las que está autorizado a acceder, y solo de formas bien definidas y permitidas. El código de tipo seguro no puede realizar una operación en un objeto que no es válido para ese objeto. Los compiladores de lenguaje C # y VB.NET siempre producen código de tipo seguro, que se verifica como tipo seguro durante la compilación JIT.

Jonuz
fuente
¿Te refieres a la seguridad de la memoria?
golopot
1

Tipo seguro significa que el conjunto de valores que pueden asignarse a una variable de programa debe ajustarse a criterios bien definidos y comprobables. Las variables de tipo seguro conducen a programas más robustos porque los algoritmos que manipulan las variables pueden confiar en que la variable solo tomará uno de un conjunto de valores bien definido. Mantener esta confianza garantiza la integridad y la calidad de los datos y el programa.

Para muchas variables, el conjunto de valores que pueden asignarse a una variable se define en el momento en que se escribe el programa. Por ejemplo, se puede permitir que una variable llamada "color" tome los valores "rojo", "verde" o "azul" y nunca otros valores. Para otras variables, esos criterios pueden cambiar en tiempo de ejecución. Por ejemplo, una variable llamada "color" solo puede tomar valores en la columna "nombre" de una tabla "Colores" en una base de datos relacional, donde "rojo", "verde" y "azul" son tres valores para "nombre" en la tabla "Colores", pero alguna otra parte del programa de computadora puede agregar a esa lista mientras el programa se está ejecutando, y la variable puede tomar los nuevos valores después de que se agreguen a la tabla Colores .

Muchos lenguajes de tipo seguro dan la ilusión de "tipo de seguridad" al insistir en definir estrictamente los tipos de variables y solo permitir que a una variable se le asignen valores del mismo "tipo". Hay un par de problemas con este enfoque. Por ejemplo, un programa puede tener una variable "yearOfBirth", que es el año en que nació una persona, y es tentador escribirlo como un número entero corto. Sin embargo, no es un entero corto. Este año, es un número menor que 2009 y mayor que -10000. Sin embargo, este conjunto crece en 1 cada año a medida que se ejecuta el programa. Hacer de esto un "int corto" no es adecuado. Lo que se necesita para hacer que esta variable sea segura es una función de validación en tiempo de ejecución que garantiza que el número sea siempre mayor que -10000 y menor que el próximo año calendario.

Los lenguajes que usan la escritura dinámica (o la escritura de pato o la escritura de manifiesto) como Perl, Python, Ruby, SQLite y Lua no tienen la noción de variables escritas. Esto obliga al programador a escribir una rutina de validación de tiempo de ejecución para cada variable para garantizar que sea correcta o soportar las consecuencias de excepciones de tiempo de ejecución inexplicables. En mi experiencia, los programadores en lenguajes estáticamente tipados como C, C ++, Java y C # a menudo se ven obligados a pensar que los tipos estáticamente definidos son todo lo que necesitan hacer para obtener los beneficios de la seguridad de tipos. Esto simplemente no es cierto para muchos programas de computadora útiles, y es difícil predecir si es cierto para cualquier programa de computadora en particular.

Lo largo y lo corto ... ¿Quieres escribir con seguridad? Si es así, escriba funciones de tiempo de ejecución para asegurarse de que cuando se asigna un valor a una variable, se ajuste a criterios bien definidos. La desventaja es que hace que el análisis de dominio sea realmente difícil para la mayoría de los programas de computadora porque tienes que definir explícitamente los criterios para cada variable de programa.

Jay Godse
fuente
2
Las variables de Python son mecanografiadas (de hecho, muy mecanografiadas). Intente hacer esto, por ejemplo: "str" ​​+ 1. Obtendrá un error. Sin embargo, los tipos se verifican en tiempo de ejecución, en lugar de en tiempo de compilación.
mipadi el