O código que converte um valor em uma representação diferente e depois o converte de volta para onde começou é ruim, mas como? [fechadas]

35

Eu estava lendo um artigo sobre más práticas de programação .

Mencionou -

"Código io-io" que converte um valor em uma representação diferente e depois o converte de volta para onde começou (por exemplo: converter um decimal em uma string e depois em um decimal ou preencher uma string e apará-la)

Não entendo por que o exemplo específico que ele dá é uma maneira ruim de escrever programas. Parece-me correto converter de volta se a situação exigir, para que o valor possa ser usado.

Alguém pode explicar mais sobre isso?

user13107
fonte
4
leitura recomendada: Discuta este $ {blog}
gnat
8
Na maioria das vezes, é apenas redundante e acontece apenas porque o programador não conhecia uma maneira melhor de conseguir o que queria. O blog dá um exemplo típico de alguns parágrafos depois: "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?- que situação seria essa?
Konrad Morawski
3
@gnat Eu não entendo como isso faz dessa uma pergunta ruim. Se você quiser, posso editá-lo para dizer "o código que converte e converte um valor ruim é ruim?" e não caberá mais nesse modelo.
djechlin
5
Recentemente, encontrei um código em Java que itera sobre uma matriz, serializando cada objeto em um objeto JSON, usando concatenação de cadeias, não um serializador JSON. O resultado foi passado para um método privado, que analisou a matriz JSON para extrair vários IDs e passou os IDs para outro lugar. Esse foi o único uso desse array JSON no sistema. Esse é o código ioiô. Não havia razão para a transformação. Poderíamos simplesmente passar os IDs dos objetos originais.
Brandon
3
decimal myValue = decimal.Parse(dataReader["myColumn"].ToString())é uma irritação minha.
Matthew

Respostas:

125

Mesmo se você fazer necessidade tanto o numérico e a representação de cadeia de um número, é melhor para converter apenas uma vez e também ficar com o valor original, em vez de converter de novo cada vez que você precisar de um ou do outro.

O princípio é, como sempre, que o código que não existe não pode ter defeitos sutis , enquanto o código que existe frequentemente existe. Isso pode parecer paranóico, mas a experiência nos ensina que é apropriado. Se você aborda a programação com uma ansiedade leve permanente de "Não sou realmente inteligente o suficiente para entender esse sistema complexo", você está no caminho certo.

Kilian Foth
fonte
5
Bem dito. Todos nós, programadores, devemos ser muito cautelosos.
Neil
58
"o código que não existe não pode ter defeitos sutis, enquanto o código que existe muitas vezes" deseja +2 você por isso. Nunca subestime o valor de não precisar escrever código.
Benjamin Gruenbaum 23/10
2
Porém, executar algumas operações simples (converter em string e voltar) pode ser muito menos complexo (mais fácil de entender e codificar) do que a maneira "correta" de manipular os bits. E manter todos os dados de uma categoria em um único formulário geralmente é uma boa ideia, mesmo que determinados dados sejam inevitavelmente convertidos em outros.
Daniel R Hicks
36
@DanielRHicks, então vamos converter essa data simples (10 de novembro de 2014) para uma string, -> 10-11-2014 e voltar para uma data -> (11 de outubro de 2014) ei, espere o quê?
Pieter B
20
@PieterB Existe um grande software de contabilidade alemão que não funciona em computadores com localidade não alemã, porque faz isso. Primeiro, converte a data em string usando o código de idioma do sistema e, em seguida, tenta analisá-lo com um código de idioma fixo e reclama do formato ilegal. Faz o mesmo com números e separadores decimais variados, exceto que não se queixa por lá, corrompe os dados e exibe um comportamento estranho. Levei dias para descobrir isso.
CodesInChaos
23

É ruim por três razões principais:

  1. Isso mostra que você não pensou em que tipo / formato a variável deveria realmente ser, mas está convertendo-a para o que você precisa naquele momento. Isso mostra falta de pensamento de design.
  2. Provavelmente é um desperdício. Você certamente está desperdiçando ciclos e linhas de código, fazendo conversões que não precisam estar lá. Isso tornará seu código mais lento e inchado do que o necessário.
  3. As conversões de tipo são propensas a erros sutis. Ao pontilhar essas conversões no seu código, você aumenta a probabilidade de erro.

Suspeito que o motivo 1 seja o motivo pelo qual sua fonte estava pensando com base no contexto em que foi mencionado.

Jack Aidley
fonte
6

Eu reformularia a descrição como "código que converte um tipo em uma representação diferente com o objetivo de fazer algo que poderia ter sido feito tão bem ou melhor no original e depois o converte novamente. Existem muitas situações em que converter algo em um um tipo diferente, agir de acordo com ela e convertê-lo de volta é totalmente apropriado, e a falha nesse procedimento resultaria em comportamento incorreto.

Como um exemplo em que a conversão é boa:
um possui quatro floatvalores de sinais arbitrários cujas magnitudes podem diferir em um fator de até 1.000 e é necessário calcular a soma para 0,625 unidades em último lugar. Converter todos os quatro valores em double, calcular a soma e converter o resultado em floatserá muito mais eficiente do que qualquer abordagem usando floatsozinha.
Os valores de ponto flutuante são precisos na melhor das hipóteses para 0,5 unidades em último lugar (ULP). Este exemplo exigiria que o erro de arredondamento do pior caso não fosse superior a 25% acima do erro ideal do pior caso. Usar um duplo produzirá um valor que será preciso dentro de 0,5001 ULP. Embora um requisito de 0,625 ULP possa parecer artificial, esses requisitos geralmente são importantes em algoritmos de aproximação sucessiva. Quanto mais rigorosamente especificado o limite de erro, menor o requisito de iteração do pior caso.

Como um exemplo em que a conversão é ruim:
um tem um número de ponto flutuante e deseja gerar uma string que representará seu valor exclusivamente. Uma abordagem é converter o número em uma string com um certo número de dígitos, tentar convertê-lo novamente e verificar se o resultado corresponde.

Mas esta é realmente uma abordagem ruim. Se uma string decimal representa um valor que fica quase precisamente no ponto intermediário entre dois valores de ponto flutuante, é bastante caro para um método string-to-float garantir que sempre produzirá o floatvalor mais próximo e muitos desses métodos de conversão não mantém tal garantia (entre outras coisas, isso exigiria, em alguns casos, a leitura de todos os dígitos de um número, mesmo que tivesse bilhões de dígitos).

É muito mais barato para um método garantir que sempre retorne um valor que esteja dentro de 0,5625 unidades em último lugar (ULP) do valor representado. Uma rotina de formatação "reversível" robusta de decimal para string deve calcular a distância do valor correto ao valor correto e continuar a produzir dígitos até que o resultado esteja dentro de 0,375 (ULP), se não 0,25 (ULP). Caso contrário, pode gerar uma string que alguns métodos de conversão processarão corretamente, mas outros não.

Às vezes, é melhor gerar um dígito que pode não ser "necessário" do que gerar um valor que possa ser mal interpretado. A parte principal é que a decisão de quantos dígitos devem ser impressos deve ser tomada com base em cálculos numéricos relacionados ao processo de impressão, e não no resultado da tentativa de um método específico de converter a string novamente em um número.

supercat
fonte
11
Seu exemplo não retorna o valor original, que é o que o OP está perguntando. Apenas retorna um valor com o mesmo tipo, calculado a partir de várias entradas.
CJ Dennis
2

Várias razões

  1. É inútil e aumenta a complexidade - tanto na quantidade de código para escrever e manter, quanto na quantidade de tempo de CPU necessária

    1. Pode perder precisão ou pior, corromper o valor inteiramente

    2. Desperdiça memória (potencialmente, dependendo do idioma) à medida que você acaba armazenando mais representações de um número necessário

Uma boa prática é apenas manter a primeira representação mais precisa possível para todos os dados que você receber. Execute quaisquer cálculos usando esses dados e apenas os converta se precisar gerá-los ou exibi-los em um formato mais fácil de ler.

Jon Story
fonte
isso não parece acrescentar nada substancial sobre os pontos levantados e explicados em respostas anteriores #
306
2
Isso justifica uma votação? Eu acredito que meu post potencialmente mais concisa
Jon História
respostas anteriores realmente olhar mais conciso para mim, ambos
mosquito
0

Por quê? Porque até os melhores de nós podem cometer erros.

Veja o que aconteceu quando a Microsoft tentou implementar um formato de "ida e volta" especificamente para garantir que as conversões de string <-> flutuantes fossem seguras: https://stackoverflow.com/q/24299692/541686

Mehrdad
fonte
0

Quando eu estava na escola (e pós-graduação em engenharia elétrica), fomos ensinados a dividir depois de multiplicar. Divisão muitas vezes muitos dígitos e são arredondados. Multiplicar após a divisão multiplica o erro de divisão.

As conversões de tipo são as mesmas, você corre o risco de perder dados. CInt (1.3) = 1.

No meu idioma, Basic, apenas fazemos conversões de tipo (um programa VB6 gasta 90% do tempo fazendo conversão ANSI / Unicode, para todas as chamadas de API que o tempo de execução faz).

A conversão de tipo está implícita em tudo o que fazemos.

 Print 5

A cadeia "5" é impressa a partir do literal numérico.

form1.caption = "My Form"

O literal da string unicode é convertido em uma string ANSI e enviado para SetWindowsTextA pelo pacote de formulários.

Mesmo isso funciona no básico

a = "5"
b = 3

c = a + b (= 8)

Hoje sou um programador de variantes - nem penso em texto. Eu apenas confio nas autoconversões.

De qualquer forma, minhas 3 irritações são

Atribuir literais de string a variáveis ​​para usá-los (desperdiça memória e lento)

Funções inúteis quando o código pode estar embutido (e o compilador provavelmente irá desfazer sua função e embutir mesmo assim)

Definir todos os objetos para nada como as últimas linhas antes de uma função final ou final do programa.

e um quarto para programas curtos

Escurecer inutilmente suas 3 variáveis ​​em um programa de 5 linhas.

triggeradeadcat
fonte