En la mayoría de los lenguajes de codificación (si no todos) necesita declarar variables. Por ejemplo, en C # si es un campo numérico, entonces
int PhoneNumber
Si estoy usando el idioma inglés normal, no necesito declarar PhoneNumber
cómo int
usarlo. Por ejemplo, si le pido a mi amigo Sam que me dé su número de teléfono, le digo:
"Sam dame el número de teléfono"
No diria
"Char (20) Sam dame el número de teléfono internacional"
¿Por qué tenemos que especificar el tipo de datos?
programming-languages
Dick Smith
fuente
fuente
Respuestas:
Esas son dos preguntas independientes:
Por cierto, la respuesta a ambas es: no lo hacemos.
Hay muchos lenguajes de programación estáticamente tipados en los que no necesita declarar tipos. El compilador puede inferir los tipos del contexto circundante y el uso.
Por ejemplo, en Scala puedes decir
o podrías decir
Los dos son exactamente equivalentes: el compilador inferirá el tipo que será
Int
de la expresión de inicialización23
.Del mismo modo, en C♯, puede decir cualquiera de estos, y ambos significan exactamente lo mismo:
Esta característica se llama inferencia de tipos , y muchos lenguajes además de Scala y C♯ la tienen: Haskell, Kotlin, Ceylon, ML, F♯, C ++, lo que sea. Incluso Java tiene formas limitadas de inferencia de tipos.
En los lenguajes de programación de tipo dinámico, las variables ni siquiera tienen tipos. Los tipos solo existen dinámicamente en tiempo de ejecución, no estáticamente. Solo los valores y las expresiones tienen tipos y solo en tiempo de ejecución, las variables no tienen tipos.
Por ejemplo, en ECMAScript:
Y, por último, en muchos idiomas, ni siquiera necesita declarar variables. Por ejemplo, en Ruby:
De hecho, ese último ejemplo es válido en varios lenguajes de programación. La misma línea de código exacta también funcionaría en Python, por ejemplo.
Asi que,
fuente
auto i = 1 // i is inferred to type int
,vector<int> vec; auto itr = vec.iterator(); // itr is inferred to type vector<int>::iterator
y así sucesivamente. Si desea saber exactamente cómo funciona eso, puede buscarlo en la especificación.Cuando usa el lenguaje natural para referirse a la información, no es muy precisa y, en particular, no se comunica mucho a los demás sobre su intención. Problemas similares ocurren cuando se intenta hacer matemáticas en lenguaje natural: simplemente no es lo suficientemente preciso.
La programación es compleja; los errores son muy fáciles de encontrar. Los tipos son parte de un sistema de controles diseñados para prevenir estados de programa ilegales, mediante la detección de condiciones de error. Los diferentes idiomas usan los tipos de manera diferente: algunos idiomas usan los tipos en gran medida para detectar errores en tiempo de compilación. Casi todos los idiomas tienen alguna noción de tipos incompatibles como error de tiempo de ejecución. Por lo general, un error de tipo indica un error de algún tipo en el programa. Cuando permitimos que los programas continúen a pesar de los errores, es probable que obtengamos respuestas muy malas. Preferimos detener el programa en lugar de obtener respuestas malas o incorrectas.
Dicho de otra manera, los tipos expresan restricciones sobre el comportamiento del programa. Las restricciones, cuando son aplicadas por algún mecanismo, brindan garantías. Dichas garantías limitan la cantidad de razonamiento necesario para pensar sobre el programa, simplificando así la tarea de leer y mantener el programa para los programadores. Sin tipos, y su implicación de herramientas (es decir, el compilador) que detectan errores de tipo, la carga de programación es considerablemente mayor y, por lo tanto, más costosa.
Es cierto que (muchos) humanos distinguen fácilmente entre un número de teléfono europeo, de Estados Unidos e internacional. Sin embargo, la computadora realmente no "piensa" y, si se le indica, marcaría un número de teléfono de Estados Unidos en Europa, o viceversa. Los tipos, por ejemplo, son una buena manera de distinguir entre estos casos, sin tener que enseñarle a la computadora cómo "pensar". En algunos idiomas, podemos obtener un error de tiempo de compilación al intentar mezclar un número de teléfono europeo en un sistema telefónico estadounidense. Ese error nos dice que necesitamos modificar nuestro programa (quizás convirtiendo el número de teléfono en una secuencia de marcado internacional o, en su lugar, utilizando el número de teléfono en Europa), incluso antes de intentar ejecutar el programa.
Además, como la computadora no piensa, el nombre del campo o variable (p
phonenumber
. Ej. ) No significa nada para la computadora. Para la computadora, ese nombre de campo / variable es simplemente "blah123". Piense en cómo sería su programa si todas las variables fueran "blahxxx". Yikes Bueno, eso es lo que ve la computadora. Proporcionar un tipo le da a la computadora una idea del significado de la variable que simplemente no puede inferir solo de su nombre.Además, como dice @Robert, en muchos idiomas modernos no tenemos que especificar los tipos tanto como en los viejos tiempos, ya que los lenguajes como C # realizan "inferencia de tipos", que es un conjunto de reglas para determinar el tipo adecuado para una variable en contexto. C # solo proporciona inferencia de tipos en variables locales, pero no en parámetros formales o campos de clase o instancia.
fuente
Types are part of a system of checks that ...
ya que responde directamente el OP elWhy do we have to specify data type at all?
..static member add x y = x + y
,member x.Append s = x.Text + s
. En el primer caso,x
yy
se deducirá que esint
s debido a la adición. En el segundo caso, serán lo que sea válido según el tipo dex.Text
- si es unstring
, entoncess
también será unstring
. Sin embargo, estoy de acuerdo en que las anotaciones de tipo son documentación.Además de las otras respuestas, hay una cosa que debe incluirse. Recuerde que las computadoras son solo bits. Digamos que te doy los bytes:
¿Qué ese medio ? La computadora lo almacena de esta manera, pero sin ninguna interpretación, son solo bits . Podrían ser 4 caracteres ascii. Podría ser un número entero. Podrían ser algunos bytes en una matriz. Podría ser parte de un objeto. Podría ser un indicador de dónde está almacenando ese video de gato. Casi todos los lenguajes de programación desde el ensamblaje en adelante necesitan algo para saber cómo interpretar los bits para que hagan un cálculo significativo.
Y dado que la computadora no puede conocer el significado de esos bits, necesita que usted lo diga, ya sea explícitamente mediante anotaciones de tipo o implícitamente mediante mecanismos de inferencia de tipo mencionados en las otras respuestas.
fuente
La respuesta a por qué las computadoras necesitan esta información tiene que ver con la Representación de datos .
El nombre del "tipo de datos" es una referencia a las reglas que ayudan a la computadora a almacenar y recuperar información de su estado bruto de 0 y 1 en la memoria de la computadora.
Por ejemplo, su carácter ASCII normal de 8 bits se almacenaría en la memoria de la computadora (RAM o Disco) como
01000001
(el carácter en mayúscula "A", código ASCII 65) o00001000
(el signo de porcentaje), o cualquier combinación de 0 y 1 en esos 8 bits.Para otro ejemplo, algunos enteros sin signo de 8 bits se pueden almacenar como
00000101
(el número 5) o00001000
(el número 8)Observe cómo la representación binaria de 8 y el carácter% pueden ser iguales, pero significan cosas diferentes porque sus tipos son diferentes.
Incluso los lenguajes que infieren el tipo de datos, pueden no tener la regla de que "todos los tipos de variables deben ser declarados por el programador", tienen reglas como "si su serie de caracteres está entre comillas, es una cadena" y muchas más reglas para cada tipo de datos.
Entonces, incluso estos necesitan tipos de datos para tener sentido de lo que significan los 0 y 1, por lo que pueden, por ejemplo, hacer la función de concatenación de cadenas si intenta "agregar" dos caracteres, o hacer la suma de enteros si está tratando de agregar dos enteros .
También en su historia , digamos que no le pidió el número de teléfono a Sam, pero Sam le da un papel que tiene escrito "1123581321". No podría estar seguro de si Sam es solo un fanático de los primeros ocho números de Fibonacci, o si ese es un número de teléfono. Para adivinar, tendrá que tener en cuenta el contexto y las señales que tiene disponibles, como tal vez le pidió a Sam un número de teléfono hace un día, o la nota dice "Llámame", o si cuenta los dígitos y encuentra coincide con los patrones de la mayoría de los números de teléfono. Solo entonces sabría que es un número de teléfono al que puede llamar y no algunos dígitos que ingresaría en una calculadora.
Observe cómo estas sugerencias que lo llevaron a adivinar que el número era un número de teléfono son similares a cómo las sugerencias conducen a un lenguaje de computadora que no requiere declaración para deducir el tipo de valor.
fuente
En algunos idiomas, no tiene que especificar el tipo de datos.
Los idiomas que admiten la inferencia de tipos generalmente pueden determinar el tipo de datos de su uso. Por ejemplo,
se escribe internamente como una cadena, porque el valor está rodeado de comillas.
Algunos idiomas tampoco requieren que declare la variable; la variable se crea cuando se usa por primera vez. Sin embargo, se considera una mejor práctica declarar específicamente sus variables, por varias razones importantes; principalmente porque hacerlo mejor expresa tu intención.
fuente
var name = "Ali"
estilo es en realidad común para los lenguajes modernos con escritura estática. En los idiomas tipados estáticamente, el tipo se fija en la creación, pero aún puede ser determinado por el inicializador. La definición de un lenguaje de tipo dinámico es que los tipos se unen a valores, no a variables. Asignar un valor a una variable, por lo tanto, establece el tipo de variables también.var x = 5; x = "";
porque la primera instrucción hacex
que el tipo "Número" esté asociadox
? Tipo de conflictos con la tipificación dinámica . Y si no, ¿qué efecto tiene el tipo asociado con la variable, más allá de la asociación de tipo con el valor?x = "";
cambia el tipo de x a cadena, incluso si era un número anteriormente.Porque eso es lo que especifica el diseño del lenguaje. Entonces, para responder a su pregunta, debemos analizar la intención detrás de la escritura explícita en lenguajes como C # y C ++. (Bueno, C # lo hace porque C ++ lo hace porque C lo hace, por lo que debemos mirar la intención en ese entonces).
Primero, el tipeo explícito y estático proporciona rigor en la codificación: la especificación de una variable como un número entero significa que el compilador y el software deben sorprenderse y arrojar un error al asignar un carácter o cadena a la variable. La escritura dinámica puede causar dolores de cabeza para los incautos (simplemente mire el enfoque PHP o javascripts para la veracidad de cosas como matrices y cadenas vacías).
Puede tener estática con la escritura implícita: inicializar una variable como una cadena significa que la variable solo debe ser una cadena, pero creo que esto puede causar problemas a los humanos que leen el código (tiendo a suponer una escritura dinámica cuando hay una escritura implícita )
Además, es posible, en algunos idiomas, escribir algo como este pseudocódigo para inicializar una clase desde una entrada de cadena:
En segundo lugar, la escritura explícita también va de la mano con la asignación de memoria. Un int es siempre tantos bytes. Un número de teléfono tiene tantos bytes. El compilador puede asignar un bloque de memoria de tamaño apropiado que luego puede usarse más adelante sin tener que ver cuánto espacio necesitará cuando asigne un valor.
Finalmente, elimina la confusión ... ¿123 es un entero o un entero sin signo? Necesitan el mismo número de bytes, pero el valor máximo almacenado en las variables de cualquier tipo es muy diferente ...
Esto no significa que explícito sea mejor que implícito, pero el diseño del lenguaje se basa en este tipo de opciones, y C # funcionaría de manera diferente con la tipificación implícita. PHP y javascript funcionarían de manera diferente con la escritura explícita.
fuente
Porque Sam es más inteligente que los compiladores. Por ejemplo, cuando dice darme el número de teléfono, no especifica si desea el prefijo del país o el código de área si es el número de trabajo donde solo se requieren los últimos 4 dígitos. Además, si solicita el número de la pizzería local, podrá responder a la respuesta "pizza4u".
Sam, se da cuenta del contexto. Si bien el compilador también puede resolverlo por contexto, Sam será mejor en eso (y es capaz de interrumpir el proceso para pedir una aclaración).
Hay dos enfoques básicos para los tipos y las variables, o la variable tiene un tipo, en cuyo caso las acciones que no están permitidas por el tipo están prohibidas y evitan la compilación, o el valor tiene un tipo y acciones que no están permitidas por el tipo tipo se capturan en tiempo de ejecución.
Cada enfoque tiene sus ventajas y desventajas. En general, los escritores de compiladores intentan minimizar las desventajas y maximizar las ventajas. Es por eso que C #, por ejemplo, permite
var phoneNumber = GetPhoneNumber();
y deducirá el tipo de número de teléfono de la firma de GetPhoneNumber. Eso significa que debe declarar el tipo para el método, pero no la variable que recibe el resultado. Por otro lado, hay varios tipos de sugerencias / proyectos para javascript. Todo es una compensación.fuente
Es una cuestión de la forma en que se almacenan los datos. Su interacción con Sam sería una mejor comparación si estuviera preguntando para poder escribirla, pero solo tenía ocho caracteres de papel.
Entonces, en cambio, la mayoría de los idiomas te hacen declarar un tipo, por lo que sabrá y se preparará con anticipación:
Se vuelve aún más difícil cuando observa las formas fundamentales reales en que se almacenan los datos. Si eres como yo, tienes un cuaderno con notas misceláneas, números garabateados, sin contexto o etiquetado para nada, y no tienes idea de lo que significa tres días después. Este también es un problema para las computadoras muchas veces. Muchos idiomas tienen tipos "int" (int, long, short, byte) y "float" (float, double). ¿Por qué es eso necesario?
Bueno, primero veamos cómo se almacena un número entero y, en general, cómo se representa dentro de la computadora. Probablemente sepa que en el nivel básico, todo es binario (1 y 0). Binary es en realidad un sistema de números que funciona exactamente como nuestro sistema de números decimales. En decimal, cuenta de 0 a 9 (con infinitos ceros iniciales implícitos que no escribe), luego vuelve a 0 e incrementa el siguiente dígito para que tenga 10. Repite hasta pasar de 19 a 20, repita hasta que pase de 99 a 100, y así sucesivamente.
Binario no es diferente, excepto que en lugar de 0 a 9, cuenta de 0 a 1. 0, 1, 10, 11, 100, 101, 110, 111, 1000. Entonces, cuando escribe 9, en la memoria que está registrada en binario como 1001. Este es un número real. Se puede sumar, restar, multiplicar, etc., exactamente de esa forma. 10 + 1 = 11. 10 + 10 = 100 (pasar 1 a 0 y llevar el 1). 11 x 10 = 110 (y equivalente, 11 + 11 = 110).
Ahora en la memoria real (registros incluidos), hay una lista, matriz, como quiera llamarlo, de bits (potenciales 1 o 0 ') uno al lado del otro, que es cómo mantiene estos bits lógicamente organizados para hacer un número mayor que 1. El problema es, ¿qué haces con los decimales? No puede simplemente insertar una pieza de hardware entre los dos bits en el registro, y costaría demasiado agregar "bits decimales" entre cada par de bits. ¿Entonces lo que hay que hacer?
Lo codificas. En general, la arquitectura de la CPU o el software determinará cómo se hace esto, pero una forma común es almacenar un signo (+ o -, generalmente 1 es negativo) en el primer bit del registro, una mantisa (su número cambió) sin embargo, muchas veces es necesario deshacerse del decimal) para el siguiente número X de bits, y un exponente (el número de veces que tuvo que cambiarlo) para el resto. Es similar a la notación científica.
Escribir le permite al compilador saber lo que está viendo. Imagine que ha almacenado el valor 1.3 en el registro 1. Vamos a encontrar nuestro propio esquema de codificación elegante aquí, 1 bit para signo, 4 para mantissa, 3 para exponente (1 bit para signo, 2 para magnitud). Este es un número positivo, por lo que el signo es positivo (0). Nuestra mantisa sería 13 (1101) y nuestro exponente sería -1 (101 (1 para negativo, 01 = 1)). Así que almacenamos 01101101 en el registro 1. Ahora no escribimos esta variable, por lo que cuando el tiempo de ejecución va a usarla, dice "claro, este es un número entero por qué no", así que cuando imprime el valor vemos 109 (64 + 32 + 8 + 4 + 1), lo que obviamente no es correcto.
Sin embargo, no todos los idiomas requieren que escribas explícitamente. C # tiene una palabra clave "var" que hace que el tipo de una variable se interprete en tiempo de compilación, y otros lenguajes como Javascript se escriben de forma totalmente dinámica, hasta el punto de que puede almacenar un número entero en una variable, luego asignarlo a un booleano, luego asignarlo de nuevo a una cadena y el idioma realiza un seguimiento de todo.
Pero es mucho más fácil para el compilador, el intérprete o el tiempo de ejecución, y a menudo resulta en un programa más rápido ya que no tiene que gastar recursos valiosos clasificando todo, para preguntarle a usted, el programador, qué tipo de datos que le estás dando.
fuente
Hay lenguajes de programación en los que no tiene que declarar tipos de datos para sus variables. Incluso hay lenguajes de programación en los que no tiene que declarar variables de antemano; sólo se puede utilizar ellos, de inmediato.
El problema con no declarar nombres de variables es que si accidentalmente escribe mal el nombre de una variable, ahora ha creado accidentalmente una nueva variable completamente no relacionada. Entonces, cuando ejecuta su programa, no puede entender por qué demonios esa variable que configuró de repente no tiene nada ... Hasta que, después de muchas horas de depuración, ¡se da cuenta de que escribió mal el maldito nombre! GRRR !!
Entonces lo hicieron para que tenga que declarar los nombres de las variables que va a usar de antemano. Y ahora, cuando escribe un nombre incorrecto, obtiene un error en tiempo de compilación, que inmediatamente le dice exactamente dónde está el error, incluso antes de que su programa se ejecute. ¿No es eso mucho más fácil?
Mismo trato con los tipos de datos. Hay lenguajes de programación donde no tienes que declarar qué tipo de cosas deberían ser. Si tiene una
customer
variable que en realidad es solo el nombre de un cliente, no todo el objeto del cliente, tratar de obtener la dirección del cliente desde una cadena normal ... no funcionará. El punto completo de la escritura estática es que el programa no compilará; se quejará en voz alta, señalando el lugar exacto donde está el problema. Eso es mucho más rápido que ejecutar su código y tratar de descubrir por qué demonios no funciona.Todas estas son características para decirle al compilador lo que tenía la intención de hacer, para que pueda verificar lo que realmente hizo y asegurarse de que tenga sentido. Eso hace posible que el compilador localice automáticamente los errores, lo cual es un gran problema.
(En el pasado lejano, no tenía que declarar subrutinas . Solo lo haría
GOSUB
a un número de línea en particular. Si quisiera pasar información entre subrutinas, establecería variables globales particulares, llame a su subrutina y luego inspeccione otras variables cuando la subrutina regresa. Pero eso hace que sea terriblemente fácil olvidarse de inicializar uno de los parámetros. Así que ahora casi todos los lenguajes de programación modernos exigen que declare qué parámetros reales toma una subrutina, por lo que podemos verificar que los haya especificado todos. )fuente
var x=1
con resultados similares. Pero eso no es nada; en Haskell, puede escribir todo su programa sin firmas tipográficas, sin embargo, todo está tipado estáticamente, y aún obtiene errores si comete un error ... (No exactamente convencional).for (auto i=0; i<SomeStdVector.size(); ++i)
su linter se quejará porque dedujo un tipo con signo y procederá a compararlo con un tipo sin signo. Tienes que escribirauto i=0ul
(poner la información de tipo explícitamente de nuevo, por lo que solo debes escribirsize_t i=0
en primer lugar).Pop a MathOverflow o la informática teórica y leer por un tiempo para tener una idea de cómo los seres humanos alogrithms entre sí comunican cuando quieren asegurar que no hay posibilidad de malos entendidos. O lea el estándar para un lenguaje de programación maduro.
Descubrirá que definir qué tipos de valores están permitidos para un término es parte de una práctica de comunicación realmente precisa, incluso de persona a persona.
Lo que ha notado es que las interacciones diarias son bastante regulares y las personas son bastante tolerantes a fallas, por lo que el conocimiento compartido de los participantes generalmente evita un malentendido sobre los números de teléfono.
Pero, ¿alguna vez has tratado de quitarle el número de teléfono a alguien en otro país? ¿Le dijeron explícitamente cuántas veces presionar cero para llegar al direccionamiento internacional? ¿Te dijeron su código de país? ¿Lo reconociste como tal? ¿Cuántos dígitos esperabas? Cuanto obtuviste? ¿Sabías cómo agrupar los dígitos? ¿O incluso si la agrupación tiene importancia?
De repente, el problema es mucho más difícil y es probable que haya tenido mucho más cuidado para verificar explícitamente que el número recibido se entendió de la manera en que lo dijo el remitente.
fuente
Otra razón para declarar tipos es la eficiencia. Mientras que un número entero podría almacenarse en 1 byte, o 2 bytes, o 4, un programa que usa una gran cantidad de variables podría usar 4 veces la memoria necesaria, dependiendo de lo que se esté haciendo. Solo el programador sabe si un espacio de almacenamiento más pequeño es viable, por lo que puede decirlo declarando el tipo.
Además, los objetos escritos dinámicamente permiten muchos tipos posibles, sobre la marcha. Eso podría incurrir en una sobrecarga "debajo del capó", ralentizando el programa en comparación con quedarse con un tipo todo el tiempo.
fuente
Varios lenguajes de programación tempranos (especialmente Fortran) no requerían que declarases variables antes de usarlos.
Esto condujo a una serie de problemas. Una muy obvia es que el compilador ya no puede detectar errores tipográficos simples de manera tan confiable. Si tiene un código que se supone que modifica una variable existente, pero tiene un error tipográfico, todavía tiene un código perfectamente legítimo que acaba de crear (y le asignó un valor) una nueva variable:
Ahora, mirando esto de forma aislada, ya que ya mencioné un error tipográfico como la fuente del problema, probablemente sea bastante fácil encontrar el error tipográfico y el problema aquí. En un programa largo, donde esto está enterrado en medio de muchos otros códigos, es mucho más fácil pasarlo por alto.
Incluso actualmente con muchos idiomas escritos dinámicamente, aún puede obtener el mismo problema básico con bastante facilidad. Algunos tienen alguna facilidad para advertirte si asignas una variable, pero nunca la lees (lo que detecta heurísticamente bastantes problemas como este), mientras que otros no tienen esas cosas.
fuente
Cuando declara cualquier variable, se asigna algo de espacio en la memoria, pero la máquina (computadora en este caso) ya no sabe cuánto espacio debe asignarse para esa variable.
Ejemplo: - crea un programa que le pide al usuario que ingrese cualquier número, en este caso tiene que especificar un tipo de datos para almacenar ese número, de lo contrario, la máquina no puede juzgar por sí misma que debería asignar 2 bytes o 2 gigabytes , si lo intenta hacer la asignación por sí mismo, puede resultar en un uso ineficiente de la memoria. Por otro lado, si especifica el tipo de datos en su programa, luego de la compilación, la máquina asignará el espacio adecuado de acuerdo con la necesidad.
fuente