Según tengo entendido, las conversiones implícitas pueden causar errores.
Pero eso no tiene sentido: ¿no deberían las conversiones normales también causar errores, entonces?
¿Por qué no tener
len(100)
trabajar por el lenguaje interpretándolo (o compilándolo) como
len(str(100))
especialmente porque esa es la única forma (que sé) de que funcione. El idioma sabe cuál es el error, ¿por qué no solucionarlo?
Para este ejemplo usé Python, aunque siento que para algo tan pequeño es básicamente universal.
programming-languages
type-conversion
Quelklef
fuente
fuente
perl -e 'print length(100);'
impresiones 3.str
la forma implícita de convertir un int en un iterable? ¿qué talrange
? obin
(hex
,oct
) ochr
(ounichr
)? Todos esos retornos iterables, incluso sistr
parece lo más obvio para usted en esta situación.Respuestas:
Por lo que vale
len(str(100))
,len(chr(100))
ylen(hex(100))
son todos diferentes. nostr
es la única forma de hacerlo funcionar, ya que hay más de una conversión diferente en Python de un entero a una cadena. Uno de ellos, por supuesto, es el más común, pero no necesariamente pasa sin decir que es a lo que te refieres. Una conversión implícita literalmente significa "no hace falta decir".Uno de los problemas prácticos con las conversiones implícitas es que no siempre es obvio qué conversión se aplicará cuando hay varias posibilidades, y esto hace que los lectores cometan errores al interpretar el código porque no logran descubrir la conversión implícita correcta. Todos siempre dicen que lo que pretendían es la "interpretación obvia". Es obvio para ellos porque es lo que querían decir. Puede que no sea obvio para alguien más.
Es por eso que (la mayoría de las veces) Python prefiere explícito a implícito, prefiere no arriesgarse. El caso principal en el que Python sí hace la coerción de tipo es en aritmética. Permite
1 + 1.0
porque la alternativa sería demasiado molesto para vivir, pero que no permite1 + "1"
ya que piensa que debería tener que especificar si quieres decirint("1")
,float("1")
,ord("1")
,str(1) + "1"
, o alguna otra cosa. Tampoco permite(1,2,3) + [4,5,6]
, aunque podría definir reglas para elegir un tipo de resultado, al igual que define reglas para elegir el tipo de resultado1 + 1.0
.Otros idiomas no están de acuerdo y tienen muchas conversiones implícitas. Cuanto más incluyen, menos obvios se vuelven. ¡Intente memorizar las reglas del estándar C para "promociones enteras" y "conversiones aritméticas habituales" antes del desayuno!
fuente
len
solo puede funcionar con un tipo, es fundamentalmente errónea.str
, ¡chr
yhex
todos devuelven el mismo tipo! Estaba tratando de pensar en un tipo diferente cuyo constructor puede tomar solo un int, pero aún no se me ocurre nada. Lo ideal sería un contenedorX
dondelen(X(100)) == 100
;-)numpy.zeros
parece un poco oscuro.a == b
,b == c
peroa == c
no es cierto.Te falta una palabra: las conversiones implícitas pueden causar errores de tiempo de ejecución .
Para un caso simple como el que muestra, está bastante claro lo que quiso decir. Pero los idiomas no pueden funcionar en los casos. Necesitan trabajar con reglas. Para muchas otras situaciones, no está claro si el programador cometió un error (usando el tipo incorrecto) o si el programador pretendía hacer lo que el código supone que pretendía hacer.
Si el código se supone incorrecto, obtendrá un error de tiempo de ejecución. Debido a que son tediosos de rastrear, muchos idiomas se equivocan al decirle que cometió un error y le permiten decirle a la computadora lo que realmente quiso decir (corregir el error o hacer la conversión explícitamente). Otros lenguajes adivinan, ya que su estilo se presta a un código rápido y fácil que es más fácil de depurar.
Una cosa a tener en cuenta es que las conversiones implícitas hacen que el compilador sea un poco más complejo. Debe tener más cuidado con los ciclos (intentemos esta conversión de A a B; ¡Uy, eso no funcionó, pero hay una conversión de B a A! Y luego también debe preocuparse por los ciclos de tamaño C y D ), que Es una pequeña motivación para evitar conversiones implícitas.
fuente
len(100)
volver3
. Me resultaría mucho más intuitivo calcular el número de bits (o bytes) en la representación de100
.len(100)
debe darle la cantidad de caracteres de la representación decimal del número 100. Pero eso es en realidad un montón de suposiciones que está haciendo, mientras que desconocen de ellos. Podría presentar argumentos sólidos por los que64
debería devolver el número de bits o bytes o caracteres de la representación hexadecimal ( -> 2 caracteres)len()
.Las conversiones implícitas son bastante posibles de hacer. La situación en la que te metes en problemas es cuando no sabes de qué manera algo debería funcionar.
Un ejemplo de esto se puede ver en Javascript, donde el
+
operador trabaja de diferentes maneras en diferentes momentos.Si uno de los argumentos es una cadena, entonces el
+
operador es una concatenación de cadenas, de lo contrario es una suma.Si se le da un argumento y no sabe si es una cadena o un número entero, y desea agregarlo, puede ser un poco complicado.
Otra forma de lidiar con esto es desde la herencia básica (de la cual se desprende Perl; ver Programación es difícil, vamos a crear secuencias de comandos ... )
En Basic, la
len
función solo tiene sentido al ser invocada en una Cadena (documentos para visual basic : "Cualquier expresión de Cadena válida o nombre de variable. Si la Expresión es de tipo Objeto, la función Len devuelve el tamaño tal como será escrito en el archivo por la función FilePut ").Perl sigue este concepto de contexto. La confusión que existe en JavaScript con la conversión implícita de tipos para el
+
operador es a veces suma y otras concatenación no ocurre en perl porque siempre+
es suma y siempre es concatenación..
Si se usa algo en un contexto escalar, es un escalar (por ejemplo, al usar una lista como escalar, la lista se comporta como si fuera un número correspondiente a su longitud). Si usa un operador de cadena (
eq
para prueba de igualdad,cmp
para comparación de cadena), el escalar se usa como si fuera una cadena. Del mismo modo, si algo se usó en un contexto matemático (==
para prueba de igualdad y<=>
para comparación numérica), el escalar se usa como si fuera un número.La regla fundamental para toda programación es "hacer lo que menos sorprende a la persona". Esto no significa que no haya sorpresas allí, pero el esfuerzo es sorprender a la persona lo menos.
Yendo a un primo cercano de perl - php, hay situaciones en las que un operador puede actuar sobre algo en contextos de cadena o numéricos y el comportamiento puede ser sorprendente para las personas. El
++
operador es uno de esos ejemplos. En números, se comporta exactamente como se esperaba. Al actuar sobre una cadena, como"aa"
, incrementa la cadena ($foo = "aa"; $foo++; echo $foo;
imprimeab
). También se volcará para queaz
cuando se incremente se hagaba
. Esto no es particularmente sorprendente todavía.( ideona )
Esto imprime:
Bienvenido a los peligros de las conversiones implícitas y los operadores que actúan de manera diferente en la misma cadena. (Perl maneja ese bloque de código de manera un poco diferente; decide que
"3d8"
cuando++
se aplica el operador es un valor numérico desde el principio y va de4
inmediato ( ideone ), este comportamiento se describe bien en perlop: incremento automático y decremento automático )Ahora, por qué un idioma hace algo de una manera y otro lo hace de otra manera llega a los pensamientos de diseño de los diseñadores. La filosofía de Perl es que hay más de una forma de hacerlo , y puedo pensar en varias formas de realizar algunas de estas operaciones. Por otro lado, Python tiene una filosofía descrita en PEP 20 - El Zen de Python que establece (entre otras cosas): "Debe haber una, y preferiblemente solo una, forma obvia de hacerlo".
Estas diferencias de diseño han llevado a diferentes idiomas. Hay una forma de obtener la longitud de un número en Python. La conversión implícita va en contra de esta filosofía.
Lectura relacionada: ¿Por qué Ruby no tiene una conversión implícita de Fixnum en String?
fuente
x
yy
de tal manera que produzca una relación de equivalencia o clasificación, pero los operadores de comparación del IIRC Python ...ColdFusion hizo la mayor parte de esto. Define un conjunto de reglas para manejar sus conversiones implícitas, tiene un único tipo de variable y listo.
El resultado es la anarquía total, donde agregar "4a" a 6 es 6.16667.
¿Por qué? Bueno, debido a que la primera de las dos variables es un número, entonces el resultado será numérico. "4a" se analiza como una fecha y se ve como "4 AM". 4 AM es 4: 00/24: 00, o 1/6 de día (0.16667). Agregue a 6 y obtendrá 6.16667.
Las listas tienen caracteres separadores predeterminados de una coma, por lo que si alguna vez agrega un elemento a una lista que contiene una coma, simplemente agrega dos elementos. Además, las listas son cadenas secretas, por lo que se pueden analizar como fechas si solo contienen 1 elemento.
La comparación de cadenas verifica si ambas cadenas se pueden analizar primero en fechas. Porque no hay tipo de fecha, lo hace. Lo mismo para los números y cadenas que contienen números, notación octal y booleanos ("verdadero" y "sí", etc.)
En lugar de fallar rápidamente e informar un error, en su lugar, ColdFusion manejará las conversiones de tipo de datos por usted. Y no en el buen sentido.
Por supuesto, puede corregir las conversiones implícitas llamando a funciones explícitas como DateCompare ... pero luego ha perdido los "beneficios" de la conversión implícita.
Para ColdFusion, esta es una forma de ayudar a capacitar a los desarrolladores. Especialmente cuando todos esos desarrolladores están acostumbrados a HTML (ColdFusion funciona con etiquetas, se llama CFML, luego también agregaron secuencias de comandos
<cfscript>
, donde no es necesario agregar etiquetas para todo). Y funciona bien cuando solo quieres que algo funcione. Pero cuando necesita que las cosas sucedan de manera más precisa, necesita un lenguaje que se niegue a hacer conversiones implícitas para cualquier cosa que parezca que podría haber sido un error.fuente
Estás diciendo que las conversiones implícitas podrían ser una buena idea para operaciones que no son ambiguas, como
int a = 100; len(a)
cuando obviamente quieres convertir el int en una cadena antes de llamar.Pero está olvidando que estas llamadas pueden ser sintácticamente inequívocas, pero pueden representar un error tipográfico realizado por el programador que pretendía pasar
a1
, que es una cadena. Este es un ejemplo artificial, pero con IDEs que proporcionan autocompletado para nombres de variables, estos errores ocurren.El sistema de tipos tiene como objetivo ayudarnos a evitar errores, y para los idiomas que eligen una verificación de tipo más estricta, las conversiones implícitas socavan eso.
Eche un vistazo a los problemas de Javascript con todas las conversiones implícitas realizadas por ==, tanto que ahora muchos recomiendan seguir con el operador de conversión no implícita ===.
fuente
Considere por un momento el contexto de su declaración. Dices que esta es la "única forma" en que podría funcionar, pero ¿estás realmente seguro de que funcionará así? ¿Qué hay de esto?
Como otros han mencionado, en su ejemplo muy específico, parece simple para el compilador intuir lo que quiso decir. Pero en un contexto más amplio de programas más complicados, a menudo no es del todo obvio si usted quiso ingresar una cadena, o tipeó un nombre de variable para otro, o llamó a la función incorrecta, o cualquiera de las docenas de otros posibles errores lógicos .
En el caso en que el intérprete / compilador adivine lo que quiso decir, a veces funciona mágicamente, y otras veces pasa horas depurando algo que misteriosamente no funciona sin razón aparente. Es mucho más seguro, en el caso promedio, que le digan que la afirmación no tiene sentido, y que pase unos segundos corrigiéndola según lo que realmente quiso decir.
fuente
Las conversiones implícitas pueden ser un verdadero dolor para trabajar. En PowerShell:
De repente, se necesitan el doble de pruebas y el doble de errores que habría sin una conversión implícita.
fuente
Los lanzamientos explícitos son importantes porque aclaran su intención. En primer lugar, el uso de modelos explícitos cuenta una historia a alguien que está leyendo su código. Revelan que intencionalmente hiciste lo que hiciste. Además, lo mismo se aplica al compilador. Lo siguiente es ilegal en C # por ejemplo
El elenco te hará perder precisión, lo que fácilmente podría ser un error. Por lo tanto, el compilador se niega a compilar. Al usar un reparto explícito, le está diciendo al compilador: "Oye, sé lo que estoy haciendo". Y él irá: "¡Está bien!" Y compilar.
fuente
(X)y
debe significar es "Creo que Y es convertible a X; hacer la conversión si es posible, o lanzar una excepción si no"; Si una conversión tiene éxito, uno debería poder predecir cuál será el valor resultante * sin tener que conocer ninguna regla especial sobre la conversión de tipoy
a tipoX
. Si se les solicita convertir -1.5 y 1.5 a enteros, algunos idiomas producirán (-2,1); algunos (-2,2), algunos (-1,1) y algunos (-1,2). Si bien las reglas de C son apenas oscuras ...Los idiomas que admiten conversiones / conversiones implícitas, o tipeo débil, como a veces se le conoce, harán suposiciones para usted que no siempre coinciden con el comportamiento que pretendía o esperaba. Los diseñadores del lenguaje pueden haber tenido el mismo proceso de pensamiento que usted para un cierto tipo de conversión o serie de conversiones, y en ese caso nunca verá un problema; sin embargo, si no lo hicieron, entonces su programa fallará.
Sin embargo, la falla puede o no ser obvia. Dado que estas conversiones implícitas se producen en tiempo de ejecución, su programa se ejecutará felizmente y solo verá un problema cuando observe el resultado o el resultado de su programa. Un lenguaje que requiere conversiones explícitas (algunos se refieren a esto como tipeo fuerte) le daría un error incluso antes de que su programa comience la ejecución, lo cual es un problema mucho más obvio y más fácil de solucionar que las conversiones implícitas salieron mal.
El otro día, un amigo mío le preguntó a su hijo de 2 años qué era 20 + 20 y él respondió 2020. Le dije a mi amigo: "Se convertirá en un programador de Javascript".
En Javascript:
Por lo tanto, puede ver los problemas que pueden crear los moldes implícitos y por qué no es algo que solo se pueda solucionar. La solución, diría, es usar modelos explícitos.
fuente