Devo reutilizar variáveis?


59

Devo reutilizar variáveis?

Eu sei que muitas práticas recomendadas dizem que você não deve fazê-lo, no entanto, mais tarde, quando um desenvolvedor diferente estiver depurando o código e tiver três variáveis ​​parecidas e a única diferença é que elas são criadas em locais diferentes no código. confuso. O teste de unidade é um ótimo exemplo disso.

No entanto, eu não sei que as melhores práticas são na maioria das vezes contra ele. Por exemplo, eles dizem para não "substituir" os parâmetros do método.

As práticas recomendadas são contra a anulação das variáveis ​​anteriores (no Java, há o Sonar que emite um aviso ao atribuir nullà variável, que você não precisa fazer isso para chamar o coletor de lixo desde o Java 6. Você nem sempre pode controlar quais avisos estão desativados; na maioria das vezes o padrão está ativado.)


11
Desde o Java 6? Você nunca precisou atribuir nulo a variáveis ​​em nenhuma versão do Java. Quando uma variável sai do escopo, ela libera a referência ao seu objeto.
Kevin Panko

35
re-uso de variáveis é um dos primeira coisa que código-obfuscators usar
Lelouch Lamperouge

7
A reutilização de variáveis ​​entra em conflito com a escolha de identificadores decentes para suas variáveis. Nas línguas modernas, não há realmente nenhuma vantagem na reutilização de variáveis ​​que supere os benefícios de ter bons identificadores.
Joren

4
Observe também que nem todas as reutilizações são reutilizadas. Os programadores antigos do FORTRAN, mesmo aqueles que se deslocaram para outras linguagens, usam rotineiramente I, J, K, L, M, N (ou i, j, k, l, m, n) para todo o nosso loop DO (for- contadores). Estamos acostumados a ver coisas como SUM = SUM + A (I, K) * B (K, J) ou soma + = a [i] [k] * b [k] [j] ;.
John R. Strohm

11
A reutilização de variáveis ​​pode ser justificada ao programar microcontroladores com recursos muito limitados (alguns kBytes de RAM).
m.Alin

Respostas:


130

Seu problema aparece apenas quando seus métodos são longos e estão executando várias tarefas em uma sequência. Isso torna o código mais difícil de entender (e, portanto, manter) por si só. Reutilizar variáveis ​​adiciona, além disso, um elemento extra de risco, tornando o código ainda mais difícil de seguir e mais propenso a erros.

A melhor prática da IMO é usar métodos curtos o suficiente que façam apenas uma coisa, eliminando todo o problema.


e quanto ao teste de unidade? por exemplo, preciso testar se, depois de executar o método pela segunda vez, ele ainda funciona conforme o esperado.
IAdapter 21/10

20
@IAdapter, o código de teste de unidade é um problema diferente, onde os padrões podem ser mais relaxados do que no código de produção. Ainda assim, torná-lo legível e fácil de manter é de alta prioridade. Você também pode (e deve) extrair métodos de seus testes de unidade, para mantê-los curtos e fáceis de ler (e para eliminar a necessidade de reutilizar variáveis).
Péter Török

3
@IAdapter, para o cenário que você descreveu, não reutilizaria uma variável. O apropriado seria algo como result1 = foo(); result2 = foo(); Assert.AreEqual(result1, result2);eu não estou vendo muitos lugares em que você precisaria reutilizar uma variável nesse caso.
usar o seguinte comando

11
@IAdapter for (int i = 0; i <2; i ++) {resultado = foo (); assertEquals (resultado esperado, resultado);} #
Bill K

2
+1 - este é um bom código para quando criar métodos menores.

49

A reutilização variável de um método é um forte sinal de que você deve refatorar / dividi-lo.

Portanto, minha resposta seria que você não deveria reutilizá-los, porque, se o fizer, seria muito mais difícil refatorá-lo mais tarde.


19

Depende.

Algumas variáveis ​​podem ser criadas exatamente com a finalidade de manter um determinado tipo de dados, que pode mudar durante a execução de uma função. Os códigos de retorno vêm à mente aqui, por exemplo:

void my_function() {
    HRESULT errorcode;
    errorcode = ::SomeWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
    errorcode = ::AnotherWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
}

O nome da variável deixa muito claro o que essa variável pretende armazenar. Eu acho que outros casos de uso como esse são possíveis, onde uma variável é conceitualmente um contêiner que é logicamente usado por diferentes instâncias de coisas muito semelhantes durante o curso de uma função.

No entanto, em geral, isso deve ser feito apenas em circunstâncias em que seja absolutamente claro para possíveis leitores do código. Em nenhum caso, exceto talvez otimização extrema sem considerar a legibilidade do código, uma variável deve ser reutilizada apenas porque o tipo se encaixa.

Tudo isso resulta basicamente de boas práticas em nomeação de variáveis. Os nomes devem falar por si. Se for difícil definir o objetivo exato de todas as reutilizações em um nome abreviado, é melhor usar apenas variáveis ​​distintas.


15

A maior razão pela qual não reutilizo variáveis ​​(especialmente em testes de unidade) é porque ela introduz um caminho de código desnecessário, difícil de testar e depurar. Um bom teste de unidade deve ser independente de outros testes e, quando você reutilizar a variável de nível de classe (instância) em um equipamento de teste de unidade, você deve garantir a afirmação de seu estado antes de cada teste. Um bom teste de unidade também isola os defeitos; portanto, em teoria, cada caso de teste (método) deve apenas afirmar 1 comportamento para o sistema em teste. Se seus métodos de teste são escritos assim, raramente há uma necessidade ou benefício em reutilizar uma variável no nível do método. Por fim, em idiomas que oferecem suporte a fechamentos e processamento assíncrono, é realmente difícil argumentar sobre o que diabos está acontecendo se você estiver reutilizando variáveis ​​em um método.


então, eu deveria escrever métodos de teste como -testSomething e afirmar a invocação de método único -testSomethingTwoInvocations e asserts para apenas a segunda invocação?
IAdapter 21/10

2
Sim. Ele ajuda a identificar se a primeira ou a segunda iteração falhou. O mspec pode ajudar nisso, sua árvore de herança será muito útil.
Bryan Boettcher

Se você usar "variável" quando quiser dizer "variável de classe" ou "variável de instância", precisará se expressar com mais clareza.
gnasher729

13

Você deve usar variáveis ​​diferentes. Se você está preocupado que seu colega fique confuso, dê-lhes nomes que cubram claramente seus papéis.
A reutilização de variáveis ​​é uma provável fonte de confusão no futuro; melhor esclarecer agora.
Em alguns casos, o mesmo nome de variável pode ser reutilizado; por exemplo, iem um loop de contagem simples. Nesses casos, é claro que você deve garantir que as variáveis ​​estejam em seu próprio escopo.

EDIT: reutilizar variáveis ​​às vezes é um sinal de que o princípio de responsabilidade única é violado. Verifique se a variável reutilizada é usada na mesma função. Se for, pode não ser reutilizado (embora ainda seja preferível ter duas variáveis ​​diferentes, para restringir o escopo dessas variáveis). Se for usado em diferentes funções, você terá uma violação do SRP em suas mãos.


4

Há uma situação em que você pode reutilizar uma variável, independentemente dos ótimos conselhos dados por outras respostas: quando o seu compilador precisa de ajuda.

Em alguns casos, seu compilador pode não ser inteligente o suficiente para perceber que uma determinada variável alocada no registro não está mais sendo usada pela próxima parte do código. Portanto, ele não reutilizará esse registro livre teoricamente para as próximas variáveis, e o código gerado poderá ficar abaixo do ideal.

Observe que eu não conheço nenhum compilador mainstream atual que não consiga capturar essa situação corretamente; portanto, nunca faça isso, a menos que você saiba que seu compilador está gerando um código abaixo do ideal. Se você estiver compilando para sistemas embarcados especiais com compiladores personalizados, ainda poderá enfrentar esse problema.


17
-1, a menos que você possa apontar para uma situação do mundo real onde isso realmente acontece e onde reutilizar uma variável faz uma diferença apreciável. Esta é uma solução teórica para um problema teórico, e não é muito boa nisso. Onde o compilador decide colocar variáveis ​​é a preocupação do compilador; se o seu compilador gerar código incorreto e se realmente fizer diferença, corrija ou substitua o compilador.
Caleb

3
@Caleb - você nem sempre tem acesso ao código-fonte do compilador para a plataforma em que está desenvolvendo, especialmente para plataformas incorporadas proprietárias. eu também DID dizer em minha resposta que eu não sei de nenhum compiladores mainstream atual (ou intérpretes / VMs na verdade) que não executar corretamente esta análise liveness em todos os casos que eu olhei. No entanto, eu tenho trabalhado em sistemas embarcados proprietários com compiladores personalizados que foram muito bare-ossos no passado (10 anos ou mais). O sistema era muito limitado em capacidade, assim como o compilador, portanto essa situação ocorreu lá.
Joris Timmermans

2
+1 Fiz exatamente essa reutilização no projeto anterior (código de mídia altamente otimizado escrito em ANSI C). Tanto quanto me lembro, a diferença era facilmente visível na montagem e mensurável nos benchmarks. Nunca fiz isso e espero que nunca tenha que fazer tal reutilização em Java.
mosquito

A correção ou substituição do compilador do @Caleb pode não ser uma opção por vários motivos, e você simplesmente precisa se contentar com o que possui.

@ ThorbjørnRavnAndersen É concebível que alguém seja forçado a usar um compilador ruim e, além disso, que o desempenho seja tão crítico que você precise adivinhar o compilador e manipular seu código para reutilizar um registro? Sim. É provável ? Não. MadKeithV concorda que ele não pode fornecer um exemplo do mundo real. É uma prática recomendada ? É um bom estilo ? É um indicador de qualidade do código ? Definitivamente não. Esta é uma resposta útil para a pergunta escrita? Devido respeito a MadKeithV, mas acho que não.
Caleb

2

Eu diria NÃO.

Pense neste cenário: seu programa travou e você precisa descobrir o que aconteceu inspecionando um dump principal ... você pode ver a diferença? ;-)


Se o seu dump principal for de uma construção otimizada, as variáveis ​​podem compartilhar a memória de qualquer maneira. Portanto, isso é menos útil do que pode ser.
Winston Ewert 22/10

é claro, uma compilação otimizada não é muito útil para depuração! mas, de qualquer forma, você ainda tem a opção de usar uma compilação de depuração ... E quando você tem o depurador conectado, não precisa ir passo a passo desde o início de uma função para ver como as variáveis ​​mudam, porque elas não! :-D
fortran

2

Não, você não está melhorando o código que a máquina está executando (... o código de montagem). Deixe reutilizar qualquer memória que o compilador use para a variável no compilador. Muitas vezes, será um registro e a reutilização não lhe trouxe nada. Concentre-se em tornar o código mais fácil de ler.


0

Depende. Em uma linguagem dinâmica, em que o tipo reside em valores e não em variáveis, se eu tivesse um argumento bem nomeado para uma função que, por exemplo, fosse uma string. Uma mudança no algoritmo significava que ele sempre era usado após ser interpretado como um número inteiro; então, como um primeiro rascunho, eu poderia fazer o equivalente a

escreva = int (escreva)

Mas eu acabaria procurando alterar o tipo enviado para a função e observando a alteração no tipo de parâmetro.


11
Colocar uma linha como "scrote = int (scrote)" no meio de um longo lote de código é uma ótima maneira de enlouquecer os programadores de manutenção.
Jhocking 21/10

É mais provável que o problema esteja no "longo lote de código" que você mencionou.
Paddy3118

Bem como as notas de resposta aceitas, reutilizar variáveis ​​é realmente apenas um problema com longos lotes de código. Basicamente, em qualquer situação em que você escreveria algo como "scrote = int (scrote)", eu preferiria colocar int (scrote) em uma nova variável ou, melhor ainda, passar int (scrote) para uma nova função.
Jhocking

0

Primeiro, observe o seu ambiente de desenvolvimento. Se você tiver problemas para depurar porque possui cinco variáveis ​​em escopos diferentes com nomes idênticos e o depurador não mostra qual dessas variáveis ​​é a que você precisa, não use cinco variáveis ​​com o mesmo nome. Há duas maneiras de conseguir isso: Use uma variável ou cinco nomes diferentes.

Seu depurador também pode dificultar a depuração de uma função com muitas variáveis. Se uma função com 20 variáveis ​​for mais difícil de depurar do que uma com 16 variáveis, considere substituir 5 variáveis ​​por uma. ("Pode considerar" não é o mesmo que "deveria sempre").

Não há problema em usar uma variável em vários locais, desde que a variável sempre tenha o mesmo objetivo. Por exemplo, se dez chamadas de função retornarem um código de erro, que é tratado imediatamente para cada chamada, use uma variável e não 10. Mas não use a mesma variável para coisas completamente diferentes. Como usar "nome" para o nome de um cliente e 10 linhas depois usando a mesma variável para o nome de uma empresa, isso é ruim e causará problemas. Pior ainda, use "customerName" para um nome de cliente e 10 linhas depois usando a mesma variável "customerName" para um nome de empresa.

Importante, nada é uma regra de ferro. Tudo tem vantagens e desvantagens. Se as "melhores práticas" sugerirem uma coisa e você tiver motivos para dizer que é uma má ideia em sua situação específica, não faça isso.


0

Primeiro, observe o seu ambiente de desenvolvimento. Se você tiver problemas para depurar porque possui cinco variáveis ​​em escopos diferentes com nomes idênticos e o depurador não mostra qual dessas variáveis ​​é a que você precisa, não use cinco variáveis ​​com o mesmo nome. Há duas maneiras de conseguir isso: Use uma variável ou cinco nomes diferentes.

Seu depurador também pode dificultar a depuração de uma função com muitas variáveis. Se uma função com 20 variáveis ​​for mais difícil de depurar do que uma com 16 variáveis, considere substituir 5 variáveis ​​por uma. ("Pode considerar" não é o mesmo que "deveria sempre").

Não há problema em usar uma variável em vários locais, desde que a variável sempre tenha o mesmo objetivo. Por exemplo, se dez chamadas de função retornarem um código de erro, que é tratado imediatamente para cada chamada, use uma variável e não 10. Há um problema com isso: Geralmente, o compilador informará quando você usa uma variável não inicializada. Mas aqui, se você ler o código de erro após a chamada 6, mas a variável não tiver sido realmente alterada após a chamada 5, você obterá dados inúteis sem que o compilador o avise. Porque a variável foi inicializada, com dados que agora são inúteis.

Importante, nada é uma regra de ferro. Tudo tem vantagens e desvantagens. Se as "melhores práticas" sugerirem uma coisa e você tiver motivos para dizer que é uma má ideia em sua situação específica, não faça isso.


-2

Use variáveis ​​globais quando precisar manter um estado ou armazenar constantes. Reutilizando variáveis, você está reutilizando apenas o nome que aponta para um local na memória. Os nomes descritivos nas inicializações podem obter clareza (assumindo Java e sem TOC primitivo).

A menos que você goste de ofuscar o código manualmente ou irritar outros desenvolvedores.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.