Tipo de datos

Un tipo de datos ( type ) es un conjunto de valores y operaciones sobre estos valores (IEEE Std 1320.2-1998) [1] .

Otras definiciones:

Un tipo define los posibles valores y su significado, operaciones y cómo se almacenan los valores del tipo. Estudiado por la teoría de tipos . Una parte integral de la mayoría de los lenguajes de programación son los sistemas de tipos , que utilizan tipos para proporcionar cierto grado de seguridad de tipos .

Definición

El tipo de datos caracteriza al mismo tiempo:

La primera propiedad puede verse como una definición teórica de conjuntos de la noción de tipo; la segunda es como una definición procedimental (o conductual).

Además, en la programación, se utiliza una definición de bajo nivel de un tipo, como características dimensionales y estructurales dadas de una celda de memoria, en la que se puede colocar un cierto valor correspondiente a estas características. Tal definición es un caso especial de la teoría de conjuntos. En la práctica, se le asocian varias propiedades importantes (debido a las peculiaridades de la organización de la memoria de la computadora ), que requieren una consideración por separado .

La definición de teoría de conjuntos, especialmente en su variante de bajo nivel, se usa más comúnmente en la programación imperativa . La definición procedimental está más asociada con el polimorfismo paramétrico . La programación orientada a objetos utiliza la definición procedimental cuando describe la interacción de los componentes del programa, y ​​la definición teórica de conjuntos cuando describe la implementación de estos componentes en una computadora, respectivamente, considerando " clase como comportamiento " y " clase como objeto en la memoria ". " .

La operación de asignar un tipo a las entidades de información se denomina digitación . La verificación de asignación y consistencia de tipo se puede realizar por adelantado ( tipado estático ), directamente en el uso ( tipado dinámico ) o una combinación de ambos métodos. Los tipos se pueden asignar "de una vez por todas" ( tipificación fuerte ) o permitir que cambien ( tipificación débil ).

Los tipos evitan la paradoja de Russell , en particular, Church introdujo tipos en el cálculo lambda con este mismo propósito [6] .

En el lenguaje natural, los pronombres interrogativos son los encargados de escribir .

El tratamiento uniforme de datos de diferentes tipos se denomina polimorfismo [7] [8] .

El concepto de seguridad de tipo se basa principalmente en la definición de tipo procedimental. Por ejemplo, un intento de dividir un número por una cadena será rechazado por la mayoría de los idiomas, ya que no se define un comportamiento correspondiente para estos tipos. Los lenguajes débilmente tipeados tienden a ser definiciones de bajo nivel. Por ejemplo, " número " y " registro " tienen un comportamiento diferente, pero el valor de la dirección de " registro " en la memoria de la computadora puede tener la misma representación de bajo nivel que "número". Los lenguajes débilmente tipificados brindan la capacidad de romper el sistema de tipos asignando un comportamiento de " número " a un valor a través de una operación de conversión . Dichos trucos se pueden usar para aumentar la eficiencia de los programas, pero conllevan el riesgo de fallas y, por lo tanto, no están permitidos en lenguajes seguros o están estrictamente aislados.

Clasificación

Existen varias clasificaciones de tipos y reglas para su asignación.

Por analogía con las matemáticas, los tipos de datos se dividen en escalares ( primitivos ) y no escalares ( agregados ). Un valor de tipo no escalar (un valor no escalar) tiene muchos componentes visibles para el usuario, mientras que un valor de tipo escalar (un valor escalar) no. [9] Ejemplos de un tipo no escalar son matrices , listas , etc.; ejemplos de un tipo escalar son " entero ", " booleano ", etc.

Los tipos estructurales (agregados) no deben identificarse con estructuras de datos : algunas estructuras de datos están directamente incorporadas por ciertos tipos estructurales, pero otras se construyen a través de su composición, la mayoría de las veces recursivas. En este último caso, se habla de tipos de datos recursivos . Un ejemplo de estructuras de datos que casi siempre se construyen a través de la composición de objetos de tipo recursivo son los árboles binarios .

Según otra clasificación, los tipos se dividen en independientes y dependientes . Las variedades importantes de estos últimos son los tipos de referencia , que, a su vez, son punteros . Las referencias (incluidos los punteros) son un tipo dependiente no compuesto, cuyos valores son la dirección en la memoria de la computadora de otro valor. Por ejemplo, en el sistema de tipo C , el tipo " puntero a un entero sin signo " se escribe como " unsigned *" , en el lenguaje ML , el tipo " referencia a un entero sin signo " se escribe como " word ref" .

Los tipos también se dividen en monomórficos y polimórficos (ver variable de tipo ).

Algunos tipos de datos comunes

Tipo booleano

Los valores lógicos o booleanos (después del nombre de su inventor, Boole), pueden tener solo uno de dos estados: "verdadero" o "falso". En diferentes idiomas se denotan boolpor , BOOLo boolean. "Verdad" se puede denotar como true, TRUEo #T. "Falso", respectivamente, false, FALSEo #F. En C y C++, cualquier número distinto de cero se trata como verdadero y el cero se trata como falso. En Python , a algunos tipos individuales también se les asigna un valor "booleano". En principio, un bit es suficiente para implementar el tipo, sin embargo, debido a la naturaleza de los microprocesadores, en la práctica el tamaño de los valores booleanos suele ser igual al tamaño de una palabra de máquina .

Tipos enteros

Los tipos enteros contienen valores interpretados como números (con y sin signo).

Números de punto flotante

Se utiliza para representar números reales (no necesariamente enteros). En este caso, el número se escribe como x=a*10^b. Donde 0<=a<1 y b es un número entero de un cierto rango. a se llama la mantisa, b es el orden. La mantisa almacena varios dígitos después del punto decimal y b se almacena en su totalidad.

Tipos de cadenas

Una secuencia de caracteres que se trata como un todo en el contexto de una variable. Diferentes lenguajes de programación imponen diferentes restricciones en las variables de cadena. Las cadenas pueden contener secuencias de escape .

Punteros

Un puntero es una variable cuyo rango de valores consiste en direcciones de ubicaciones de memoria o un valor especial para indicar que actualmente no hay nada almacenado en la variable.

Tipos de identificación

Los tipos de identidad no se interpretan como un número, sino como un identificador de objeto único. Por ejemplo, FourCC .

Tipos de datos abstractos

Tipos de datos que se consideran independientemente del contexto y la implementación en un lenguaje de programación particular. La abstracción en el sentido matemático significa que el álgebra de datos se trata hasta el isomorfismo . Los tipos abstractos se utilizan ampliamente en la metodología de programación basada en el desarrollo de programas paso a paso. En la etapa de construcción de la especificación del programa diseñado, el álgebra de datos modela los objetos del área temática, en términos del problema a resolver. En el proceso de refinamiento incremental, los datos se concretan pasando a representaciones intermedias hasta que se encuentra su implementación utilizando el álgebra de datos subyacente del lenguaje de programación utilizado. Hay varias formas de definir los tipos abstractos: algebraica, modelo y axiomática. En el enfoque del modelo, los elementos de datos se definen explícitamente. El enfoque algebraico usa métodos de relaciones algebraicas, mientras que el enfoque axiomático usa formalización lógica.

Ejemplos

Auto-aplicación

Un tipo puede ser parametrizado por otro tipo, de acuerdo con los principios de abstracción y parametricidad . Por ejemplo, para implementar una función de clasificación de secuencias, no es necesario conocer todas las propiedades de sus elementos constituyentes -solo es necesario que permitan una operación de comparación- y entonces el tipo compuesto “ secuencia ” puede definirse como paramétricamente polimórfico . . Esto significa que sus componentes no se definen utilizando tipos concretos (como " integer " o " array of integers "), sino parámetros de tipo. Dichos parámetros se denominan variables de tipo ( variable de tipo en inglés  ); se utilizan en la definición de un tipo polimórfico de la misma manera que los parámetros de valor en una definición de función. La sustitución de tipos concretos como parámetros reales por un tipo polimórfico produce un tipo monomórfico. Así, un tipo paramétricamente polimórfico es un constructor de tipos , es decir, un operador sobre tipos en la aritmética de tipos.

Definir una función de clasificación como paramétricamente polimórfica significa que clasifica una secuencia abstracta, es decir, una secuencia de elementos de algún tipo (desconocido). En este caso, la función necesita conocer solo dos propiedades sobre su parámetro: que es una secuencia y que la operación de comparación está definida para sus elementos . Considerar los parámetros de una manera procesal en lugar de declarativa (es decir, usarlos en función del comportamiento en lugar del valor) le permite usar una sola función de clasificación para cualquier secuencia: para secuencias de enteros, para secuencias de cadenas, para secuencias de secuencias de valores booleanos. valores, etc., y aumenta significativamente el factor de reutilización del código . La escritura dinámica proporciona la misma flexibilidad , sin embargo, a diferencia del polimorfismo paramétrico , el primero viene con sobrecarga. El polimorfismo paramétrico está más desarrollado en lenguajes tipo Hindley-Milner , es decir, descendientes del lenguaje ML . En la programación orientada a objetos , el polimorfismo paramétrico se denomina programación genérica .

A pesar de las ventajas obvias del polimorfismo paramétrico, a veces es necesario proporcionar un comportamiento diferente para diferentes subtipos del mismo tipo general, o un comportamiento similar para tipos incompatibles, es decir, en alguna forma de polimorfismo ad-hoc . Sin embargo, no existe una base matemática para ello, por lo que el requisito de seguridad del tipo dificultó su uso durante mucho tiempo. El polimorfismo ad-hoc se implementó dentro de un sistema de tipo polimórfico paramétrico a través de varios trucos. Para ello, se utilizaron tipos de variantes o módulos paramétricos ( functores o los llamados " valores indexados de tipo ") que, a su vez, también tienen una serie de implementaciones [ 10] .  Clases de tipo , introducidas en el lenguaje Haskell , proporcionó una solución más elegante a este problema.

Si la entidad de información en cuestión es un tipo, entonces asignarle un tipo conducirá al concepto de un " tipo de tipo " (" metatipo "). En la teoría de tipos, este concepto se denomina " clase de tipos " ( ing.  kind of a type o type kind ). Por ejemplo, el género “ *” incluye todos los tipos, y el género “ * -> *” incluye todos los constructores de tipos unarios . Los géneros se usan explícitamente en la programación completa de tipos  , por ejemplo, como constructores de tipos en lenguajes de la familia ML .

La extensión del sistema seguro de tipos polimórficos a clases y géneros de tipos convirtió a Haskell en el primer lenguaje totalmente tipificado . El sistema de tipos resultante ha influido en otros lenguajes (por ejemplo , Scala , Agda ).

Una forma limitada de metatipos también está presente en varios lenguajes orientados a objetos en forma de metaclases . En los descendientes del lenguaje Smalltalk (como Python ), cada entidad en un programa es un objeto que tiene un tipo que en sí mismo es un objeto; por lo tanto, los metatipos son una parte natural del lenguaje. En el lenguaje C++ , el subsistema RTTI se implementa por separado del sistema de tipo principal del lenguaje , que también proporciona información de tipo en forma de una estructura especial.

La elucidación dinámica de los metatipos se llama reflexión (y también reflexividad o introspección).

Representación informática

La diferencia más notable entre la programación real y la teoría de la información formal es la consideración de problemas de eficiencia no solo en términos de notación O , sino también desde el punto de vista de la viabilidad económica de implementar ciertos requisitos en una computadora fabricada físicamente . Y, en primer lugar, esto afecta la precisión permisible de los cálculos: el concepto de "número" en una computadora en la práctica no es idéntico al concepto de número en aritmética . El número en la computadora está representado por una celda de memoria , cuyo tamaño está determinado por la arquitectura de la computadora , y el rango de valores del número está limitado por el tamaño de esta celda. Por ejemplo, los procesadores de la arquitectura Intel x86 proporcionan celdas cuyo tamaño en bytes se establece en una potencia de dos: 1, 2, 4, 8, 16 , etc. Los procesadores de la arquitectura Setun proporcionan celdas cuyo tamaño en rasgos se establece en una múltiplo de tres: 1, 3, 6, 9, etc.

Un intento de escribir en una celda un valor que exceda el límite máximo permitido para ella (que se conoce ) da como resultado un error de desbordamiento . Si es necesario calcular sobre números mayores, se utiliza una técnica especial, denominada aritmética larga , que, debido a la gran intensidad de recursos, no se puede realizar en tiempo real. Para las arquitecturas informáticas más comunes en la actualidad, el “nativo” es el tamaño de celda de 32 y 64 bits (es decir, 4 y 8 bytes ).

Además, los números enteros y los números reales tienen diferentes representaciones en estas celdas: los enteros no negativos se representan directamente , los enteros negativos se representan en complemento a dos y los números reales se codifican de una manera especial . Debido a estas diferencias, la suma de los números " 1" y " 0.1", que en teoría da el valor " 1.1", es directamente imposible en una computadora. Para implementarlo, primero debe realizar una conversión de tipo , generando un 1nuevo valor del tipo real “ ” basado en el valor del tipo entero “ 1.0”, y solo luego agregar “ 1.0” y “ 0.1”. Debido a los detalles de la implementación de números reales en una computadora, dicha transformación no se lleva a cabo de manera absolutamente exacta, sino con cierto grado de aproximación. Por la misma razón, los lenguajes fuertemente tipados (como Standard ML ) tratan el tipo real como tipos de igualdad (o tipos de identidad) ( Equality type ).

Para la representación de bajo nivel de tipos compuestos, el concepto de alineación de datos es importante . Los lenguajes de alto nivel generalmente aíslan (abstraen) al programador de esta propiedad, sin embargo, debe tenerse en cuenta al vincular módulos compilados de forma independiente entre sí. Sin embargo, algunos lenguajes ( C - , C ++ ) brindan la capacidad de controlar la representación de tipos de bajo nivel, incluida la alineación. Dichos lenguajes a veces se denominan lenguajes de nivel medio.

Notas

  1. IEEE Std 1320.2-1998 (R2004) IEEE Standard for Conceptual Modeling Language Syntax and Semantics for IDEF1X97:
    un conjunto de valores y operaciones sobre esos valores
  2. ISO/IEC/IEEE 24765-2010 Ingeniería de sistemas y software - Vocabulario Archivado el 17 de junio de 2016 en Wayback Machine :
    una clase de datos, caracterizada por los miembros de la clase y las operaciones que se les pueden aplicar
  3. IEEE Std 1320.2-1998 (R2004) IEEE Standard for Conceptual Modeling Language Syntax and Semantics for IDEF1X97:
    una categorización de un conjunto abstracto de posibles valores, características y conjunto de operaciones para un atributo
  4. ISO/IEC 19500-2:2003, Tecnología de la información - Procesamiento distribuido abierto - Parte 2: Protocolo inter-ORB general (GIOP)/Protocolo inter-ORB de Internet (IIOP):
    una categorización de argumentos de operación de valores, que generalmente cubre ambos comportamiento y representación
  5. Fecha de CJ . Sobre las diferencias lógicas entre tipos, valores y variables // Fecha en la base de datos: Escritos 2000-2006, Apress, 2006, ISBN 978-1-59059-746-0
  6. Harrison J. Introducción a la programación funcional  = http://www.cl.cam.ac.uk/Teaching/Lectures/funprog-jrh-1996/ . - 1997. Archivado el 11 de enero de 2015.
  7. Strachey, 1967 , 3.6.4. Polimorfismo, pág. 36-37.
  8. Cardelli, 1991 , 2. Lenguajes tipificados, p. 5.
  9. Fecha KJ, 2005 .
  10. Valores indexados por tipo . Consultado el 15 de julio de 2014. Archivado desde el original el 21 de abril de 2016.

Literatura