language-agnostic programming-languages computer-science terminology type-safety

language agnostic - ¿Qué es el tipo seguro?



language-agnostic programming-languages (11)

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

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

Memoria**

Un caracter suele requerir 1 byte por carácter, u 8 bits (depende del idioma, Java y C # almacenan los caracteres Unicode que requieren 16 bits). Un int requiere 4 bytes, o 32 bits (generalmente).

Visualmente:

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

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

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

int >> char:

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

En el caso anterior, los 3 bytes a la derecha se sobrescriben, por lo que cualquier puntero a esa memoria (por ejemplo, 3 caracteres consecutivos) que espera obtener un valor char predecible ahora tendrá basura. Esto causa undefined comportamiento undefined en su programa (o peor aún, 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, el tipo de idioma seguro lo aborda de manera inherente y describe visualmente el problema para 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 asignado de 32 bits, pero cuando el valor de un int sin signo se lee en el espacio de un int (o viceversa), nuevamente tenemos undefined comportamiento undefined . Imagine los problemas que esto podría causar en un programa bancario:

"¡Amigo! Sobregrabado $ 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 deben 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 el 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 del todo malo.

Una razón por la que estos lenguajes son tan rápidos computacionalmente es que no se cargan al verificar la compatibilidad de tipos durante las 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.

¿Qué significa "seguro para el tipo"?


La seguridad de tipo significa que el compilador validará los tipos mientras compila, y emitirá 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 de los métodos, ya que les estás pasando tipos explícitos:

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

Si intentara llamar a eso usando:

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

El compilador arrojaría un error, porque estoy pasando una cadena ("5") y está esperando un entero.

En un lenguaje escrito a la ligera, como javascript, puedo hacer lo siguiente:

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

si lo llamo asi

Sum = AddTwoNumbers(5, "5");

Javascript convierte automáticamente el 5 en una cadena y devuelve "55". Esto se debe a javascript utilizando el signo + para la concatenación de cadenas. Para que sea consciente del tipo, deberías 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 asi

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 indisponibles como javascript (de hecho, un lenguaje dinámico no implica un lenguaje impreciso (ver Python)), algunos de ellos le darán un error de ejecución en la conversión de tipos no válidos.

Si bien es conveniente, le abre una gran cantidad de errores que pueden perderse fácilmente, y que solo se pueden identificar al probar el programa en ejecución. Personalmente, prefiero que mi compilador me diga si cometí ese error.

Ahora, de vuelta a C # ...

C # admite una función de lenguaje llamada covariance , 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 subclases Barra. Ahora puedo crear un método:

void DoSomething(Bar myBar)

Y llámelo usando un Foo, o una Barra 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 pasarle 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 he salido del extremo profundo y más allá del alcance de la pregunta original, pero es bueno saberlo todo :)


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

Un lenguaje seguro para el tipo es aquel en el que las únicas operaciones que uno puede ejecutar en los datos son las que están aprobadas por el tipo de datos. Es decir, si sus datos son del tipo X y X no admiten la operación y , entonces el idioma no le permitirá ejecutar y(X) .

Esta definición no establece reglas sobre cuándo se verifica 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 con tipos estáticos le permiten convertir datos de un tipo a otro, y la validez de los conversos debe verificarse en tiempo de ejecución (imagine que está intentando enviar un Object a un Consumer : el compilador no tiene forma de saber si es aceptable o no).

La seguridad de tipos no significa necesariamente una tipificación fuerte, ya que algunos lenguajes son notoriamente tipificados de manera débil, pero aún así se podría decir que son seguros. Tome Javascript, por ejemplo: su sistema de tipos es tan débil como viene, pero aún así está estrictamente definido. Permite la conversión automática de datos (por ejemplo, cadenas a ints), pero dentro de reglas bien definidas. No tengo conocimiento de que un programa de Javascript se comporte de manera indefinida, y si eres lo suficientemente inteligente (no lo soy), deberías poder predecir lo que sucederá al leer el código de Javascript.

Un ejemplo de lenguaje de programación inseguro para el tipo 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 tipo, pero no es de tipo seguro.


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

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


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

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

Ahora para el texto largo.

Tipo de seguridad significa prevenir errores de tipo. El error de tipo se produce cuando el tipo de datos de un tipo se asigna a otro tipo de forma DESARROLLADA 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 código a continuación, los resultados son "55", pero el punto importante es la confusión creada sobre el tipo de operación que realizará.

Esto está sucediendo porque javascript no es un tipo de lenguaje seguro. Está permitiendo establecer un tipo de datos para 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 lenguaje de tipo seguro. No permite que un tipo de datos se asigne a otro tipo de datos. El código siguiente no permite al operador "+" en diferentes tipos de datos.


Prueba esta explicación en ...

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

Para el comportamiento no tipográfico, considere esto:

object x = 89; int y;

Si intentas hacer esto:

y = x;

el compilador genera un error que dice que no puede convertir un objeto System.Object en un entero. Necesitas hacer eso explícitamente. Una forma sería:

y = Convert.ToInt32( x );

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

En ASP.NET abundan las colecciones no seguras para los tipos (por ejemplo, las colecciones de aplicaciones, sesiones y estados de vista). La buena noticia sobre estas colecciones es que (al minimizar las consideraciones de administración del estado de varios servidores) puede colocar prácticamente cualquier tipo de datos en cualquiera de las tres colecciones. La mala noticia: debido a que estas colecciones no son seguras para los tipos, tendrá que emitir los valores de manera adecuada cuando los recupere.

Por ejemplo:

Session[ "x" ] = 34;

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

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

Lea acerca de los genéricos para conocer las formas en que la instalación lo ayuda a implementar fácilmente colecciones de tipos seguros.

C # es un lenguaje de escritura segura, pero busque artículos sobre C # 4.0; se vislumbran interesantes posibilidades dinámicas (es una buena cosa que C # esencialmente esté obteniendo Option Strict: Off ... ya veremos).


Tipo de seguridad significa que el conjunto de valores que pueden asignarse a una variable de programa debe ajustarse a criterios verificables y bien definidos. 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 del 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, a una variable llamada "color" se le puede permitir tomar los valores "rojo", "verde" o "azul" y nunca otros valores. Para otras variables, esos criterios pueden cambiar en tiempo de ejecución. Por ejemplo, a una variable llamada "color" solo se le puede permitir tomar valores en la columna "nombre" de una tabla de "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 agregarse a esa lista mientras el programa se está ejecutando, y la variable puede tomar los nuevos valores después de agregarlos a la tabla de Colores .

Muchos idiomas seguros para el tipo dan la ilusión de "seguridad de tipo" al insistir en definir estrictamente los tipos para las variables y solo permitir que se asignen valores a la misma variable 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 escribirla como un entero corto. Sin embargo, no es un entero corto. Este año, es un número que es 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 esto un "int corto" no es adecuado. Lo que se necesita para que esta variable sea segura para el tipo es una función de validación en tiempo de ejecución que asegure que el número sea siempre mayor que -10000 y menor que el año calendario siguiente. No hay un compilador que pueda imponer tales criterios porque estos criterios son siempre características únicas del dominio del problema.

Los idiomas que utilizan la tipificación dinámica (o tipografía de pato o tipografía de manifiesto) como Perl, Python, Ruby, SQLite y Lua no tienen la noción de variables tipificadas. Esto obliga al programador a escribir una rutina de validación en tiempo de ejecución para cada variable para garantizar que sea correcta, o soportar las consecuencias de las excepciones de tiempo de ejecución inexplicables. En mi experiencia, los programadores en lenguajes de tipo estático como C, C ++, Java y C # a menudo se sienten confiados al pensar que los tipos definidos estáticamente es 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.

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


Tipo de seguridad significa que mediante programación, el tipo de datos para una variable, valor de retorno o argumento debe ajustarse a un cierto criterio.

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

PHP, Javascript y otros lenguajes dinámicos de scripting suelen ser de tipo débil, ya que convertirán una (cadena) "7" en un (entero) 7 si intentas agregar "7" + 3, aunque a veces tienes 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" en su lugar. La seguridad de tipos evita estos tipos de errores en el código al hacer explícito el requisito de tipo.

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


Type-Safe es un código que accede solo a las ubicaciones de memoria a las que está autorizado para acceder, y solo en formas bien definidas y permitidas. El código de seguridad de tipo 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 seguro durante la compilación JIT.


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

  1. No puedes leer de variables sin inicializar
  2. No puedes indexar matrices más allá de sus límites
  3. No se pueden realizar conversiones de tipos sin marcar.

Una explicación de un estudiante de artes liberales, no un título de ciencia ficción:

Cuando la gente dice que una función de idioma o idioma es segura, significa que el idioma ayudará a evitar que, por ejemplo, pase algo que no sea un número entero a alguna lógica que espere un número entero.

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

void foo(int arg)

El compilador entonces me impedirá hacer esto:

// call foo foo("hello world")

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

Los lenguajes seguros de tipo intentan capturar más en "tiempo de compilación".

En el lado negativo, con lenguajes 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 una int, o cuando tiene una 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.