Existem argumentos de engenharia de software objetivos e compatíveis a favor ou contra a modificação dos valores dos parâmetros por valor no corpo de uma função?
Uma briga recorrente (principalmente de boa diversão) na minha equipe é se os parâmetros passados por valor devem ou não ser modificados. Alguns membros da equipe são inflexíveis aos quais os parâmetros nunca devem ser atribuídos, para que o valor passado originalmente para a função possa sempre ser interrogado. Não concordo e afirmo que os parâmetros nada mais são do que variáveis locais inicializadas pela sintaxe de chamar o método; se o valor original de um parâmetro por valor for importante, uma variável local poderá ser declarada para armazenar explicitamente esse valor. Não estou confiante de que um de nós tenha um apoio muito bom à nossa posição.
Esse é um conflito religioso não resolvível ou existem boas razões objetivas de engenharia de software em qualquer direção?
Nota: A questão do princípio permanece independentemente dos detalhes de implementação do idioma específico. Em JavaScript, por exemplo, onde a lista de argumentos é sempre dinâmica, os parâmetros podem ser considerados como açúcar sintático para a inicialização da variável local a partir do arguments
objeto. Mesmo assim, pode-se tratar os identificadores declarados por parâmetros como "especiais" porque eles ainda capturam a passagem de informações do chamador para o chamado.
fonte
Respostas:
Adotei uma terceira posição: parâmetros são como variáveis locais: ambos devem ser tratados como imutáveis por padrão. Portanto, as variáveis são atribuídas uma vez e somente lidas, não alteradas. No caso de loops,
for each (x in ...)
a variável é imutável no contexto de cada iteração. As razões para isso são:Diante de um método com várias variáveis atribuídas e que não mudam, posso me concentrar na leitura do código, em vez de tentar lembrar o valor atual de cada uma dessas variáveis.
Diante do mesmo método, desta vez com menos variáveis, mas que mudam de valor o tempo todo, agora tenho que lembrar o estado atual dessas variáveis, além de trabalhar no que o código está fazendo.
Na minha experiência, o primeiro é muito mais fácil para o meu cérebro ruim. Outros, pessoas mais inteligentes e inteligentes que eu não podem ter esse problema, mas isso me ajuda.
Quanto ao outro ponto:
versus
Exemplos planejados, mas, na minha opinião, é muito mais claro o que está acontecendo no segundo exemplo devido aos nomes das variáveis: eles transmitem muito mais informações ao leitor do que aquela massa de
r
no primeiro exemplo.fonte
for
loops com variáveis imutáveis. Encapsular a variável na função não é suficiente para você? Se você está tendo problemas para seguir suas variáveis em uma mera função, talvez suas funções sejam muito longas.for (const auto thing : things)
é um loop for, e a variável que ele introduz é imutável (localmente).for i, thing in enumerate(things):
também não se transformar qualquer moradoresEssa é uma coisa que eu realmente gosto em C ++ (bem escrito): você pode ver o que esperar.
const string& x1
é uma referência constante,string x2
é uma cópia econst string x3
é uma cópia constante. Eu sei o que vai acontecer na função.x2
será alterado, porque se não fosse, não haveria razão para torná-lo não-const.Portanto, se você tiver um idioma que permita , declare o que está prestes a fazer com os parâmetros. Essa deve ser a melhor escolha para todos os envolvidos.
Se o seu idioma não permitir isso, receio que não exista solução de bala de prata. Ambos são possíveis. A única orientação é o princípio da menor surpresa. Adote uma abordagem e siga-a por toda a sua base de código, não a misture.
fonte
int f(const T x)
eint f(T x)
só são diferentes no corpo da função.const int x
apenas para esclarecer x não é alterada por dentro? Parece um estilo muito estranho para mim.const
lista de parâmetros se isso o impedir. Então, acho que isso não responde à pergunta.Sim, é um "conflito religioso", exceto que Deus não lê programas (tanto quanto eu sei), então é rebaixado para um conflito de legibilidade que se torna uma questão de julgamento pessoal. E eu certamente fiz isso, e vi isso feito, nos dois sentidos. Por exemplo,
Então aqui, apenas por causa do nome do argumento t0 , eu provavelmente escolheria não alterar seu valor. Mas suponha que apenas mudássemos o nome do argumento para tNow ou algo assim. Então, muito mais do que provável, esqueci uma cópia local e simplesmente escrevi tNow + = dt; para essa última afirmação.
Mas, pelo contrário, suponha que eu soubesse que o cliente para quem o programa foi escrito está prestes a contratar alguns novos programadores com muito pouca experiência, que estariam lendo e trabalhando nesse código. Então eu provavelmente me preocuparia em confundi-los com passagem por valor versus referência, enquanto suas mentes estão 100% ocupadas tentando digerir toda a lógica de negócios. Portanto, nesse tipo de caso, eu sempre declararia uma cópia local de qualquer argumento que será alterado, independentemente de ser mais ou menos legível para mim.
As respostas para esse tipo de questão de estilo surgem com a experiência e raramente têm uma resposta religiosa canônica. Qualquer um que pense que há uma resposta única (e que ele sabe disso) provavelmente precisa de mais experiência.
fonte