El código que convierte un valor en una representación diferente y luego lo vuelve a convertir a donde comenzó es malo, pero ¿cómo? [cerrado]

35

Estaba leyendo un artículo sobre malas prácticas de programación .

Mencionó

"Código YoYo" que convierte un valor en una representación diferente, luego lo convierte de nuevo a donde comenzó (por ejemplo: convertir un decimal en una cadena y luego volver a un decimal, o rellenar una cadena y luego recortarla)

No entiendo por qué el ejemplo particular que da es una mala manera de escribir programas. Me parece bien volver a convertir si la situación lo requiere para poder usar el valor.

¿Alguien puede explicar más sobre esto?

usuario13107
fuente
44
lectura recomendada: Discuta esto $ {blog}
mosquito
8
La mayoría de las veces es redundante y ocurre solo porque el programador no conocía una mejor manera de obtener lo que quería. La entrada del blog da un ejemplo típico de unos párrafos más adelante: "Roundabout code" that accomplishes in many instructions what could be done with far fewer (eg: rounding a number by converting a decimal into a formatted string, then converting the string back into a decimal). if the situation is so that they have to be used?- ¿Qué situación sería esa?
Konrad Morawski
3
@gnat No entiendo cómo eso hace que esta sea una mala pregunta. Si lo desea, puedo editarlo para decir "¿es malo el código que convierte y vuelve a convertir?" y ya no se ajustará a esa plantilla.
djechlin
55
Recientemente encontré código en Java que itera sobre una matriz, serializando cada objeto en un objeto JSON, usando la concatenación de cadenas, no un serializador JSON. Luego, el resultado se pasó a un método privado, que analizó la matriz JSON para extraer un grupo de ID, luego pasó los ID en otro lugar. Este fue el único uso de esa matriz JSON en el sistema. Ese es el código yo-yo. No había razón para la transformación de ida y vuelta. Podríamos simplemente haber pasado los ID de los objetos originales.
Brandon
3
decimal myValue = decimal.Parse(dataReader["myColumn"].ToString())es una manía mía.
Mateo

Respuestas:

125

Incluso si haces necesidad tanto la numérica y la representación de cadena de un número, que es mejor para convertir sólo una vez y también se aferran a su valor original, en lugar de convertir de nuevo cada vez que necesite uno o el otro.

El principio es, como siempre, que el código que no existe no puede tener defectos sutiles , mientras que el código que existe a menudo sí. Eso puede sonar paranoico, pero la experiencia nos enseña que es apropiado. Si te acercas a la programación con una leve ansiedad permanente de "No soy realmente lo suficientemente inteligente como para entender este complejo sistema", estás en el camino correcto.

Kilian Foth
fuente
55
Bien dicho. Todos los programadores debemos ser muy cautelosos.
Neil
58
"el código que no existe no puede tener defectos sutiles, mientras que el código que existe a menudo sí" desearía poder +2 por eso. Nunca subestimes el valor de no tener que escribir código.
Benjamin Gruenbaum
2
Pero hacer un par de operaciones simples (convertir a cadena y viceversa) puede ser mucho menos complejo (más fácil de entender y codificar) que la forma "correcta" de manipular los bits. Y mantener todos los datos de una categoría en una sola forma suele ser una buena idea, incluso si ciertos datos se convertirán inevitablemente en otras formas.
Daniel R Hicks
36
@DanielRHicks, así que vamos a convertir esa fecha simple (10 de noviembre de 2014) en una cadena, -> 10-11-2014 y volver a una fecha -> (11 de octubre de 2014) oye, ¿qué?
Pieter B
20
@PieterB Hay un gran software de contabilidad alemán que no funciona en computadoras con una configuración regional no alemana porque lo hace. Primero convierte la fecha en una cadena usando la configuración regional del sistema y luego intenta analizarla con una configuración regional fija y se queja del formato ilegal. Hace lo mismo con los números y los separadores decimales variables, excepto que no se queja allí, corrompe los datos y exhibe un comportamiento extraño. Me tomó días resolver eso.
CodesInChaos
23

Es malo por tres razones principales:

  1. Muestra que no ha pensado qué tipo / formato debería ser realmente la variable, sino que la está convirtiendo a lo que necesita en ese momento. Esto muestra falta de pensamiento de diseño.
  2. Probablemente sea un desperdicio. Seguramente está desperdiciando ciclos y líneas de código, haciendo conversiones que no necesitan estar allí. Esto hará que su código sea más lento e hinchado de lo necesario.
  3. Las conversiones de tipos son propensas a errores sutiles. Al puntear estas conversiones a través de su código, aumenta la probabilidad de error.

Sospecho que la razón 1 es la razón por la que su fuente estaba pensando en función del contexto en el que se mencionó.

Jack Aidley
fuente
6

Me gustaría reformular la descripción como "código que convierte un tipo a una representación diferente con el propósito de hacer algo que podría haber hecho igual de bien o mejor en el original y luego se convierte de nuevo. Hay muchas situaciones en las que convierten algo a una tipo diferente, actuando sobre ella, y convertir de nuevo es totalmente apropiado y el fracaso para hacerlo daría lugar a un comportamiento incorrecto.

Como un ejemplo donde la conversión es bueno:
Uno tiene cuatro floatvalores de señales arbitrarias cuyas magnitudes pueden diferir en un factor de hasta 1000, y uno tiene que calcular la suma a dentro de 0,625 unidades en el último lugar. La conversión de los cuatro valores que double, calculando la suma, y la conversión de la parte posterior resultado a floatserá mucho más eficiente que sería cualquier enfoque usando floatsolo.
valores de coma flotante son en el mejor de una precisión de 0,5 unidades en el último lugar (ULP). En este ejemplo se requeriría que el peor de los casos el error de redondeo en no más del 25% por encima óptima peor caso de error. El uso de un doble producirá un valor que será preciso dentro de 0,5001 ULP. Mientras que un requisito ULP 0.625 puede parecer ideado, tales requisitos son a menudo importantes en los algoritmos de aproximación sucesiva. se especifica con más fuerza la cota de error, menor es el requisito iteración peor de los casos.

Como un ejemplo donde la conversión es malo:
Uno tiene un número de coma flotante, y desea dar salida a una cadena que representará su valor de forma única. Un método consiste en convertir el número en una cadena con un cierto número de dígitos, tratar de convertirlo de nuevo, y ver si los Resultados de los partidos.

Pero este es realmente un enfoque pobre. Si una cadena decimal representa un valor que se encuentra casi exactamente en el punto medio entre dos valores de coma flotante, que es bastante caro para un método de cadena-a-flotador para garantizar que siempre va a producir cuanto más floatvalor, y muchos de estos métodos de conversión don No mantenga esa garantía (entre otras cosas, hacerlo requeriría en algunos casos leer todos los dígitos de un número, incluso si tenía miles de millones de dígitos).

Es mucho más barato que un método garantice que siempre devolverá un valor que esté dentro de 0.5625 unidades en el último lugar (ULP) del valor representado. Una rutina de formato de decimal a cadena "reversible" robusta debe calcular qué tan lejos está el valor de salida del valor correcto y continuar emitiendo dígitos hasta que el resultado esté dentro de 0.375 (ULP) si no 0.25 (ULP). De lo contrario, puede generar una cadena que algunos métodos de conversión procesarán correctamente, pero otros métodos de conversión no.

A veces es mejor generar un dígito que podría no ser "necesario" que generar un valor que podría ser malinterpretado. La parte clave es que la decisión de cuántos dígitos deben emitirse debe basarse en cálculos numéricos relacionados con el proceso de salida, en lugar del resultado del intento de un método en particular de convertir la cadena de nuevo en un número.

Super gato
fuente
1
Su ejemplo no devuelve el valor original, que es lo que pregunta el OP. Simplemente devuelve un valor con el mismo tipo, calculado a partir de múltiples entradas.
CJ Dennis
2

Varias razones

  1. Es inútil y añade complejidad - tanto en la cantidad de código para escribir y mantener, y necesitaba la cantidad de tiempo de CPU

    1. Puede perder precisión o peor, corromper el valor por completo

    2. Pierde memoria (potencialmente, dependiendo del idioma) a medida que termina almacenando más representaciones de un número que necesita

Una buena práctica es sólo para mantener la primera representación, lo más exacta posible, para cualquier dato que recibe. Realice los cálculos con estos datos y solo conviértalos si necesita generarlos o mostrarlos en un formato más fácil de leer.

Jon Story
fuente
Esto no parece agregar nada sustancial sobre los puntos hechos y explicados en respuestas anteriores
mosquito
2
¿Eso justifica un voto negativo? Creo que mi publicación es potencialmente más concisa
Jon Story
las respuestas anteriores en realidad me parecen más concisas, ambas
mosquito
0

¿Por qué? Porque incluso los mejores de nosotros podemos cometer errores.

Mire lo que sucedió cuando Microsoft intentó implementar un formato de "ida y vuelta" específicamente para asegurarse de que las conversiones de cadena flotante <-> fueran seguras: https://stackoverflow.com/q/24299692/541686

Mehrdad
fuente
0

Cuando estaba en la escuela (y después de la escuela en ingeniería eléctrica) nos enseñaron a dividir después de multiplicar. División a menudo muchos dígitos y se redondean. Multiplicar después de la división multiplica el error de división.

Las conversiones de tipos son las mismas, corre el riesgo de perder datos. CInt (1.3) = 1.

En mi lenguaje, Basic, solo hacemos conversiones de tipo (un programa VB6 pasa el 90% de su tiempo haciendo conversión ANSI / Unicode, para todas las llamadas API que realiza el tiempo de ejecución).

La conversión de tipos está implícita en todo lo que hacemos.

 Print 5

La cadena "5" se imprime desde el literal numérico.

form1.caption = "My Form"

El literal de cadena Unicode se convierte en una cadena ANSI y se envía a SetWindowsTextA por el paquete de formularios.

Incluso esto funciona en básico

a = "5"
b = 3

c = a + b (= 8)

Soy un programador de variantes en estos días, ni siquiera pienso en el tipo. Solo confío en las conversiones automáticas.

De todos modos mis 3 manías son

Asignación de literales de cadena a variables para usarlos (desperdicia memoria y ralentiza)

Funciones sin sentido cuando el código podría estar en línea (y el compilador probablemente deshacerá su función y la alineará de todos modos)

Establecer todos los objetos en nada como las últimas líneas antes de una función final o final del programa.

y un cuarto para programas cortos

Atenúa sin sentido sus 3 variables en un programa de 5 líneas.

triggeradeadcat
fuente