Alterar o tipo de uma variável no meio de um procedimento em um estilo de linguagem digitada dinamicamente é ruim?

8

No Python (e ocasionalmente no PHP), onde as variáveis ​​não têm tipos fixos, frequentemente executarei 'transformações de tipo' em uma variável parcialmente através da lógica do meu código. Não estou (necessariamente) falando sobre conversões simples, mas sobre funções que alteram o tipo de uma variável, deixando-a basicamente representando o mesmo valor ou dados.

Por exemplo, eu poderia escrever um código como esse ao fazer uma solicitação da Web, usando a responsevariável para armazenar um objeto addurlinfo, o conteúdo da string desse objeto e o dicionário retornado analisando a string como JSON:

response = urlopen(some_url)
assert response.info().type == 'application/json'

response = response.read()
logger.debug('Received following JSON response: ' + response)

response = json.loads(response)
do_something(response)

(Ok, é um exemplo um pouco artificial, mas acho que demonstra bem a ideia). Meu sentimento é que isso é melhor do que usar três nomes de variáveis ​​separados porque: a) transmite que a responsevariável contém basicamente a mesma informação, apenas 'transformada' em um tipo diferente; eb) transmite que os objetos anteriores não ser necessário ainda mais na função, pois, ao redesignar sua variável, eu as tornei indisponíveis para o código posterior.

A desvantagem, eu acho, é que o leitor pode ficar confuso sobre que tipo de variável é a qualquer momento.

Esse estilo é ruim e devo usar três variáveis ​​diferentes no exemplo acima em vez de reatribuir a uma? Além disso, essa prática padrão é em linguagens de tipo dinâmico, ou não? Não vi o código suficiente de outras pessoas para saber.

Mark Amery
fonte

Respostas:

9

Eu vou sair em um galho e dizer: Não, isso é uma péssima idéia.

É apenas um caso especial de reutilização de uma variável, o que é uma péssima idéia - principalmente porque dificulta a compreensão do que uma variável contém em qualquer ponto do fluxo do programa. Veja, por exemplo, devo reutilizar variáveis?

Sobre seus pontos: Os pontos que você levanta são válidos, é apenas que reutilizar a variável não é uma boa solução :-).

a) transmite que a variável resposta contém basicamente a mesma informação, apenas 'transformada' em um tipo diferente

Fornecer essas informações é uma boa ideia. No entanto, não faça isso usando a mesma variável, pois você obscurece o fato de que as informações foram transformadas. Em vez disso, use nomes com um pré / postfix comum. No seu exemplo:

rawResponse = urlopen(some_url)
[...]    
jsonResponse = response.read()
[...]    
responseData = json.loads(response)
[...]

Isso deixa claro que as variáveis ​​estão intimamente relacionadas, mas também que não contêm os mesmos dados.

b) transmite que os objetos anteriores não serão mais necessários na função, pois, ao redesignar sua variável, eu os deixei indisponíveis para o código posterior.

Novamente, comunicar isso "não é mais necessário" é bom, mas não faça isso reutilizando a variável: a atribuição de reutilização geralmente será difícil de ver, portanto você só confunde o leitor.

Em vez disso, se uma variável vive muito tempo após seu último uso, isso é uma indicação de que o método / função é muito longo. Divida a parte com as variáveis ​​de vida curta em uma subfunção; isso facilita a leitura do código e limita a vida útil da variável.

Nota: Eu geralmente dou um passo além de não reutilizar variáveis ​​e tento atribuir um valor apenas uma vez (ou seja, nunca alterar o valor, torná-lo imutável). Essa é uma ideia principalmente de linguagens funcionais, mas achei que pode tornar o código muito mais claro. Obviamente, em linguagens não funcionais, às vezes você precisa alterar uma variável (exemplo óbvio sendo uma variável de loop), mas quando começar a procurar, verá que, na maioria dos casos, uma variável "nova" torna mais legível e menos código propenso a erros.

sleske
fonte
6

Eu sei que você está lendo uma URL no seu exemplo, mas se você tentasse a mesma coisa com um arquivo, não conseguiria fechar o arquivo porque a resposta não está mais apontando para o arquivo, agora está segurando uma picada recuperada do arquivo.

Esse é o grande perigo, você pode esquecer que valor ele possui, pois muda durante a vida útil do programa ou módulo. Será confuso para alguém que esteja lendo seu código, porque nunca saberá que tipo de valor está mantendo.

Estes são os bugs divertidos que tentam esmagar.

mhoran_psprep
fonte
4

Em geral, eu diria que sim, é um estilo ruim, mas há casos em que é necessário e útil reutilizar uma variável; Eu apenas recomendo evitar o uso casual e preguiçoso dele.

O problema com o seu exemplo não é por causa da digitação dinâmica, mas porque você usa a mesma variável para se referir a três coisas diferentes. Esse código é menos claro para mim porque, quando o leio, tenho que pensar muito mais para descobrir a que responsese refere.

Você pode fazer algo similarmente desagradável em uma linguagem estaticamente tipada como Java (com a restrição de que as coisas diferentes estejam relacionadas por meio de uma hierarquia de tipos). O ponto principal é que o uso de uma única variável para apontar para diferentes objetos pode ser confuso, independentemente do tipo de sistema.


fonte
Parece uma objeção razoável, e acho que vou tentar eliminar esse tipo de estilo do meu código. Acompanhamento: como você nomearia variáveis ​​diferentes que conceitualmente se referem à mesma coisa, mas com tipos diferentes? Notação húngara é tipo de feio, e arrastando os tipos (como ter response_addurlinfo, response_str, response_dict) são mais feio ainda. O que você faz?
Mark Amery
@ MarkAmery Acho que a chave é que as variáveis não se referem conceitualmente à mesma coisa. A primeira é apenas uma resposta do servidor que pode ser um erro, a segunda é uma sequência de texto que pode não ser válida json e a terceira é uma estrutura de dados. Há mais semântica do que apenas uma resposta e um tipo. Na minha experiência, uma boa nomeação de variáveis ​​é muito difícil, mas geralmente vale a pena. Desculpe, não posso ser mais concreto!