En informática y programación informática , un tipo de datos (o simplemente tipo ) es una colección o agrupación de valores de datos, generalmente especificados por un conjunto de valores posibles, un conjunto de operaciones permitidas sobre estos valores y/o una representación de estos valores como tipos de máquina. [1] Una especificación de tipo de datos en un programa restringe los posibles valores que una expresión , como una variable o una llamada de función, podría tomar. En el caso de los datos literales, le indica al compilador o intérprete cómo pretende utilizar los datos el programador. La mayoría de los lenguajes de programación admiten tipos de datos básicos de números enteros (de tamaños variables), números de punto flotante (que se aproximan a los números reales ), caracteres y booleanos . [2] [3]
Un tipo de datos puede especificarse por muchas razones: similitud, conveniencia o para centrar la atención. Con frecuencia, se trata de una cuestión de buena organización que facilita la comprensión de definiciones complejas. Casi todos los lenguajes de programación incluyen explícitamente la noción de tipo de datos, aunque los tipos de datos posibles suelen estar restringidos por consideraciones de simplicidad, computabilidad o regularidad. Una declaración explícita de tipo de datos normalmente permite al compilador elegir una representación eficiente de la máquina, pero no se debe descartar la organización conceptual que ofrecen los tipos de datos. [4]
Diferentes lenguajes pueden usar diferentes tipos de datos o tipos similares con diferentes semánticas. Por ejemplo, en el lenguaje de programación Python , int
representa un entero de precisión arbitraria que tiene las operaciones numéricas tradicionales como suma, resta y multiplicación. Sin embargo, en el lenguaje de programación Java , el tipo int
representa el conjunto de enteros de 32 bits que van en valor desde −2,147,483,648 a 2,147,483,647, con operaciones aritméticas que se ajustan en caso de desbordamiento . En Rust, este tipo entero de 32 bits se denota y entra en pánico en caso de desbordamiento en el modo de depuración. [5]i32
La mayoría de los lenguajes de programación también permiten al programador definir tipos de datos adicionales, generalmente combinando varios elementos de otros tipos y definiendo las operaciones válidas del nuevo tipo de datos. Por ejemplo, un programador podría crear un nuevo tipo de datos llamado " número complejo " que incluiría partes reales e imaginarias, o un tipo de datos de color representado por tres bytes que denotan las cantidades de cada uno de los colores rojo, verde y azul, y una cadena que representa el nombre del color.
Los tipos de datos se utilizan en los sistemas de tipos , que ofrecen diversas formas de definirlos, implementarlos y utilizarlos. En un sistema de tipos, un tipo de datos representa una restricción impuesta a la interpretación de los datos, que describe la representación, interpretación y estructura de los valores u objetos almacenados en la memoria de la computadora. El sistema de tipos utiliza la información del tipo de datos para comprobar la corrección de los programas informáticos que acceden a los datos o los manipulan. Un compilador puede utilizar el tipo estático de un valor para optimizar el almacenamiento que necesita y la elección de algoritmos para las operaciones sobre el valor. En muchos compiladores de C , el float
tipo de datos, por ejemplo, se representa en 32 bits , de acuerdo con la especificación IEEE para números de punto flotante de precisión simple . Por lo tanto, utilizarán operaciones de microprocesador específicas de punto flotante sobre esos valores (suma, multiplicación, etc. de punto flotante).
La mayoría de los tipos de datos en estadística tienen tipos comparables en programación informática, y viceversa, como se muestra en la siguiente tabla:
Estadística | Programación |
---|---|
de valor real ( escala de intervalo ) | punto flotante |
valor real ( escala de proporción ) | |
contar datos (normalmente no negativos) | entero |
datos binarios | Booleano |
datos categóricos | tipo enumerado |
vector aleatorio | lista o matriz |
matriz aleatoria | matriz bidimensional |
árbol aleatorio | árbol |
Parnas, Shore y Weiss (1976) identificaron cinco definiciones de "tipo" que se utilizaron, a veces implícitamente, en la literatura:
La definición en términos de representación se hacía a menudo en lenguajes imperativos como ALGOL y Pascal , mientras que la definición en términos de espacio de valores y comportamiento se utilizaba en lenguajes de nivel superior como Simula y CLU . Los tipos que incluyen comportamiento se alinean más estrechamente con los modelos orientados a objetos , mientras que un modelo de programación estructurada tendería a no incluir código y se denominan estructuras de datos simples .
Los tipos de datos se pueden clasificar según varios factores:
La terminología varía: en la literatura, primitivo, incorporado, básico, atómico y fundamental pueden usarse indistintamente. [8]
Todos los datos de los ordenadores basados en electrónica digital se representan como bits (alternativas 0 y 1) en el nivel más bajo. La unidad de datos direccionable más pequeña suele ser un grupo de bits llamado byte (normalmente un octeto , que son 8 bits). La unidad procesada por las instrucciones de código de máquina se denomina palabra (a partir de 2011 [actualizar], [ necesita actualización ] normalmente 32 o 64 bits).
Los tipos de datos de máquina exponen o hacen disponible un control de grano fino sobre el hardware, pero esto también puede exponer detalles de implementación que hacen que el código sea menos portable. Por lo tanto, los tipos de máquina se utilizan principalmente en la programación de sistemas o en lenguajes de programación de bajo nivel . En lenguajes de nivel superior, la mayoría de los tipos de datos son abstractos en el sentido de que no tienen una representación de máquina definida por el lenguaje. El lenguaje de programación C , por ejemplo, proporciona tipos como booleanos, enteros, números de punto flotante, etc., pero las representaciones de bits precisas de estos tipos están definidas por la implementación. El único tipo de C con una representación de máquina precisa es el char
tipo que representa un byte. [9]
El tipo booleano representa los valores true y false . Aunque solo son posibles dos valores, se representan más a menudo como una palabra en lugar de como un solo bit, ya que se requieren más instrucciones de máquina para almacenar y recuperar un bit individual. Muchos lenguajes de programación no tienen un tipo booleano explícito, sino que utilizan un tipo entero e interpretan (por ejemplo) 0 como falso y otros valores como verdaderos. Los datos booleanos se refieren a la estructura lógica de cómo se interpreta el lenguaje en el lenguaje de máquina. En este caso, un 0 booleano se refiere a la lógica False. True siempre es un valor distinto de cero, especialmente un uno, que se conoce como booleano 1.
Casi todos los lenguajes de programación proporcionan uno o más tipos de datos enteros . Pueden proporcionar una pequeña cantidad de subtipos predefinidos restringidos a ciertos rangos (como short
y long
y sus unsigned
variantes correspondientes en C/C++); o permitir a los usuarios definir libremente subrangos como 1..12 (por ejemplo, Pascal / Ada ). Si no existe un tipo nativo correspondiente en la plataforma de destino, el compilador lo descompondrá en código utilizando tipos que sí existen. Por ejemplo, si se solicita un entero de 32 bits en una plataforma de 16 bits, el compilador lo tratará tácitamente como una matriz de dos enteros de 16 bits.
Los tipos de datos de punto flotante representan ciertos valores fraccionarios ( números racionales , matemáticamente). Aunque tienen límites predefinidos tanto en sus valores máximos como en su precisión, a veces se los llama, de manera engañosa, "reales" (que evocan a los números reales matemáticos ). Por lo general, se almacenan internamente en la forma a × 2 b (donde a y b son números enteros), pero se muestran en la forma decimal familiar .
Los tipos de datos de punto fijo son convenientes para representar valores monetarios. A menudo se implementan internamente como números enteros, lo que genera límites predefinidos.
Para independizarse de los detalles de la arquitectura, se puede suministrar un tipo Bignum o de precisión arbitraria numeric
. Esto representa un entero o un número racional con una precisión limitada únicamente por la memoria disponible y los recursos computacionales del sistema. Las implementaciones Bignum de operaciones aritméticas sobre valores del tamaño de una máquina son significativamente más lentas que las operaciones de máquina correspondientes. [10]
El tipo enumerado tiene valores distintos, que pueden compararse y asignarse, pero que no necesariamente tienen una representación concreta particular en la memoria de la computadora; los compiladores e intérpretes pueden representarlos arbitrariamente. Por ejemplo, los cuatro palos de una baraja de cartas pueden ser cuatro enumeradores llamados CLUB , DIAMOND , HEART , SPADE , que pertenecen a un tipo enumerado llamado suit . Si se declara una variable V que tiene como tipo de datos el palo , se le puede asignar cualquiera de esos cuatro valores. Algunas implementaciones permiten a los programadores asignar valores enteros a los valores de enumeración, o incluso tratarlos como equivalentes de tipo a los enteros.
Las cadenas son una secuencia de caracteres que se utilizan para almacenar palabras o texto sin formato , generalmente lenguajes de marcado textual que representan texto formateado . Los caracteres pueden ser una letra de algún alfabeto , un dígito, un espacio en blanco, un signo de puntuación, etc. Los caracteres se extraen de un conjunto de caracteres como ASCII . Los tipos de caracteres y cadenas pueden tener diferentes subtipos según la codificación de caracteres. Se descubrió que el ASCII original de 7 bits de ancho era limitado y fue reemplazado por conjuntos de 8, 16 y 32 bits, que pueden codificar una amplia variedad de alfabetos no latinos (como el hebreo y el chino ) y otros símbolos. Las cadenas pueden ser de longitud variable o de longitud fija, y algunos lenguajes de programación tienen ambos tipos. También pueden tener subtipos por su tamaño máximo.
Dado que la mayoría de los conjuntos de caracteres incluyen los dígitos , es posible tener una cadena numérica, como "1234"
. Estas cadenas numéricas suelen considerarse distintas de los valores numéricos como 1234
, aunque algunos idiomas convierten automáticamente entre ellos.
Una definición de tipo de unión especificará cuál de los subtipos permitidos se puede almacenar en sus instancias, por ejemplo, "float" o "entero largo". A diferencia de un registro , que se podría definir para que contenga un float y un entero, una unión solo puede contener un subtipo a la vez.
Una unión etiquetada (también llamada variante , registro de variante, unión discriminada o unión disjunta) contiene un campo adicional que indica su tipo actual para una mayor seguridad de tipos.
Un tipo de datos algebraicos (TDA) es un tipo de suma posiblemente recursiva de tipos de productos . Un valor de un TDA consiste en una etiqueta de constructor junto con cero o más valores de campo, con el número y tipo de los valores de campo fijados por el constructor. El conjunto de todos los valores posibles de un TDA es la unión disjunta teórica de conjuntos (suma), de los conjuntos de todos los valores posibles de sus variantes (producto de campos). Los valores de los tipos algebraicos se analizan con coincidencia de patrones, que identifica el constructor de un valor y extrae los campos que contiene.
Si solo hay un constructor, entonces el TAD corresponde a un tipo de producto similar a una tupla o registro. Un constructor sin campos corresponde al producto vacío (tipo de unidad). Si todos los constructores no tienen campos, entonces el TAD corresponde a un tipo enumerado .
Un ADT común es el tipo de opción , definido en Haskell como . [11]data Maybe a = Nothing | Just a
Algunos tipos son muy útiles para almacenar y recuperar datos y se denominan estructuras de datos . Las estructuras de datos más comunes incluyen:
data List a = Nil | Cons a (List a)
data BTree a = Nil | Node (BTree a) a (BTree a)
Un tipo de datos abstracto es un tipo de datos que no especifica la representación concreta de los datos. En su lugar, se utiliza una especificación formal basada en las operaciones del tipo de datos para describirlo. Cualquier implementación de una especificación debe cumplir con las reglas dadas. Por ejemplo, una pila tiene operaciones push/pop que siguen una regla de último en entrar, primero en salir, y se pueden implementar de manera concreta utilizando una lista o una matriz. Los tipos de datos abstractos se utilizan en semántica formal y verificación de programas y, de manera menos estricta, en diseño .
El principal tipo derivado no compuesto es el puntero , un tipo de datos cuyo valor se refiere directamente a (o "apunta a") otro valor almacenado en otra parte de la memoria de la computadora utilizando su dirección . Es un tipo primitivo de referencia . (En términos cotidianos, un número de página en un libro podría considerarse un fragmento de datos que hace referencia a otro). Los punteros a menudo se almacenan en un formato similar a un entero; sin embargo, intentar desreferenciar o "buscar" un puntero cuyo valor nunca fue una dirección de memoria válida haría que un programa se bloqueara. Para mejorar este problema potencial, un tipo de puntero generalmente se considera distinto del tipo entero correspondiente, incluso si la representación subyacente es la misma.
Los lenguajes de programación funcional tratan las funciones como un tipo de datos distinto y permiten almacenar valores de este tipo en variables y pasarlos a funciones. Algunos lenguajes multiparadigma como JavaScript también tienen mecanismos para tratar las funciones como datos. [13] La mayoría de los sistemas de tipos contemporáneos van más allá del tipo simple de JavaScript "objeto de función" y tienen una familia de tipos de función diferenciados por tipos de argumento y de retorno, como el tipo Int -> Bool
que denota funciones que toman un entero y devuelven un booleano. En C, una función no es un tipo de datos de primera clase, pero los punteros de función pueden ser manipulados por el programa. Java y C++ originalmente no tenían valores de función, pero los agregaron en C++11 y Java 8.
Un constructor de tipos crea nuevos tipos a partir de los antiguos y puede considerarse como un operador que toma cero o más tipos como argumentos y produce un tipo. Los tipos de producto, los tipos de función, los tipos de potencia y los tipos de lista pueden convertirse en constructores de tipos.
Los tipos cuantificados universalmente y cuantificados existencialmente se basan en la lógica de predicados . La cuantificación universal se escribe como o y es la intersección sobre todos los tipos del cuerpo , es decir, el valor es del tipo para cada . La cuantificación existencial se escribe como o y es la unión sobre todos los tipos del cuerpo , es decir, el valor es del tipo para algún .forall x. f x
x
f x
f x
x
exists x. f x
x
f x
f x
x
En Haskell, la cuantificación universal se utiliza comúnmente, pero los tipos existenciales deben codificarse transformándolos exists a. f a
en forall r. (forall a. f a -> r) -> r
un tipo similar.
Un tipo de refinamiento es un tipo dotado de un predicado que se supone que es válido para cualquier elemento del tipo refinado. Por ejemplo, el tipo de números naturales mayores que 5 puede escribirse como
Un tipo dependiente es un tipo cuya definición depende de un valor. Dos ejemplos comunes de tipos dependientes son las funciones dependientes y los pares dependientes. El tipo de retorno de una función dependiente puede depender del valor (no solo del tipo) de uno de sus argumentos. Un par dependiente puede tener un segundo valor cuyo tipo depende del primer valor.
Un tipo de intersección es un tipo que contiene aquellos valores que son miembros de dos tipos especificados. Por ejemplo, en Java la clase Boolean
implementa tanto las interfaces Serializable
como las Comparable
. Por lo tanto, un objeto de tipo Boolean
es un miembro del tipo Serializable & Comparable
. Considerando los tipos como conjuntos de valores, el tipo de intersección es la intersección teórica de conjuntos de y . También es posible definir un tipo de intersección dependiente, denotado , donde el tipo puede depender del término variable . [14]
Algunos lenguajes de programación representan la información de tipo como datos, lo que permite la introspección y la reflexión sobre los tipos . Por el contrario, los sistemas de tipos de orden superior , si bien permiten construir tipos a partir de otros tipos y pasarlos a funciones como valores, normalmente evitan basar las decisiones computacionales en ellos. [ cita requerida ]
Para mayor comodidad, los lenguajes de alto nivel y las bases de datos pueden proporcionar tipos de datos del "mundo real" ya preparados, por ejemplo, horas, fechas y valores monetarios (moneda). [15] [16] Estos pueden estar integrados al lenguaje o implementados como tipos compuestos en una biblioteca. [17]
La implementación define cuál de los siguientes [signo y magnitud, complemento a dos, complemento a uno] se aplica.
Hace algún tiempo describí a MONEY como un tipo de datos de "conveniencia" que es efectivamente lo mismo que DECIMAL(19,4), [...]
{{cite book}}
: CS1 maint: location missing publisher (link)