Função retorna apenas parâmetro inalterado, inútil?

15

Acabei de encontrar essa função no projeto em que estou trabalhando:

  -- Just returns the text unchanged.
  -- Note: <text> may be nil, function must return nil in that case!
  function Widget:wtr(text)
      return text
  end

Muito triste, o codificador não funciona mais na empresa. Por que alguém criaria uma função que não faz nada, mas retorna o parâmetro com o qual é chamado?

Existe alguma utilidade para essa função, não especificada neste exemplo, mas global em qualquer caso?

Devido a

function aFunction(parameter)
    return parameter
end

Termina em

aFunction(parameter) == parameter

Por que eu escreveria algo como

aFunction(parameter) == whatIWantToCheck

ao invés de

parameter == whatIWantToCheck

?

Sempie
fonte
13
@gnat Como na Terra isso é uma duplicata?
Kilian Foth
13
Hã? Esta função retorna seu parâmetro - o encadeamento envolve retornar this.
Kilian Foth
11
@gnat A questão é por que alguém escreveria uma função que não faz nada, exceto retornar a si mesma. Sim, você pode retornar certos objetos ou valores para permitir o encadeamento de métodos, mas essa não é a pergunta dele. Sua pergunta é por que alguém escreveria algo como: int getParam(int param) { //DO NOTHING return param; } De uma perspectiva de encadeamento de métodos, é uma chamada completamente redundante e desnecessária, pois você pode deixar a função do OP fora de uma cadeia de métodos e isso não faria nenhuma diferença.
ZeroStatic
4
Isso provavelmente é offtopic e não se aplica ao lua, mas há um caso de uso válido para isso no PHP - em versões mais antigas, new Foo()->method();não havia sintaxe válida e construções como function with($what) { return $what; }; with(new Foo())->method();foram usadas como solução alternativa.
DCoder

Respostas:

57

Sua pergunta é como perguntar o que há de bom no número zero se, sempre que você o adiciona a algo, você obtém o mesmo valor de volta. Uma função de identidade é como o zero para funções. Meio inútil por si só, mas ocasionalmente útil como parte de uma expressão usando funções de ordem superior, onde você pode pegar uma função como parâmetro ou retorná-la como resultado. É por isso que a maioria das linguagens de programação funcionais possui uma idou identityem sua biblioteca padrão.

Em outras palavras, ele cria uma função padrão útil. Assim como você pode definir offset = 0como um número inteiro padrão, mesmo que isso faça com que um deslocamento não faça nada, pode ser útil definir filterFunction = identityuma função padrão, mesmo que isso faça com que o filtro não faça nada.

Karl Bielefeldt
fonte
Uma função de filtro não deve retornar um valor booleano? Nesse caso, a função de filtro "zero" seria a que retorna true.
Kirill Rakhman
1
@cypressious Uma função de mapa, então.
sapi 12/09/14
6
Ou para colocá-lo sob um conceito de design: padrão de objeto nulo , edição funções
blgt
@ cypressious, isso seria para um predicado que é passado como argumento para uma filterfunção de ordem superior. Uma filterfunção de primeira ordem tem o tipo [a] -> [a],
Karl Bielefeldt
Por exemplo, em C # eu costumo usar.OrderBy(x => x)
CodesInChaos
27

Certo. Imagine uma API externa que permita recuperar coisas de algum lugar absolutamente necessário, mas você deve especificar critérios de filtro e formatadores de saída para cada consulta, mesmo que deseje todos os resultados e os obtenha exatamente como armazenados.

Então você teria que inventar uma função trivial de "aceitar tudo" e uma função trivial de "retorno inalterado" para obter os dados. wtré precisamente um pseudo-formatador tão trivial. Se você usa muito essa API, pode ser muito útil ter essa função pseudo-auxiliar por aí, em vez de criar uma função anônima sempre que você consultar algo. (Você pode chamá-lo identitye não wtrpara que fique imediatamente claro que não faz nada.)

Kilian Foth
fonte
Eu realmente não entendi o sentido ainda, mas esse é exatamente o cenário. Eu posso entender depois de um tempo, trabalhando neste projeto, mantendo sua resposta em mente, eu acho. atm parece inútil para mim ... se eu tenho o rawData, porque eu iria querer uma função para me dar a rawData novamente, ...
Sempie
3
@Empie Novamente, se a API exigir uma função de formatação, a única maneira de obter o texto inalterado é se a função não fizer nada com o texto.
Doval
3
Em outras palavras: se você possui uma função que exige que os argumentos de filtro / formato sejam transmitidos e absolutamente não pode usar nullcomo argumento, use uma função de filtro vazia que filtra com 'nada' para fazer o programa parar de reclamar.
ZeroStatic
3
@Empie Você trabalhou com SQL, certo? Você sabe como incluir ou não uma WHEREcláusula? Isso é uma questão de açúcar sintático. Essencialmente, a ausência de uma WHEREcláusula é exatamente a mesma que se você tivesse uma WHEREcláusula que apenas segue em frente e permite tudo. O fato de os designers do SQL não permitirem que você especifique uma WHEREcláusula, em vez de forçá-la a colocar uma, mesmo quando ela aceita tudo, é mais ou menos açúcar sintático, e eles apenas forneceram essa opção por conveniência simples. ...
Panzercrisis
5
Pode valer a pena notar que, em muitos casos, é mais rápido e mais limpo ter o código chamar incondicionalmente um método virtual ou delegar algo que pode ou não fazer algo útil, do que ter o código para determinar se a chamada é necessária e ignorá-la.
supercat
15

Isso não é apenas um polimorfismo?

Da minha experiência com o Qt tr() e os wtr()métodos devem ser usados ​​(lá, no Qt ) na localização do Widgettexto.

Então, retornando texto inalterado este método apenas diz: Widget does no localization (translation of the text) by default. Override this function to enable your own logic.

GreenScape
fonte
1
não percebi que isso era uma coisa do QT - essa é obviamente a resposta.
Corley Brigman
8

Um caso muito comum para isso é "funcionalidade adicionada posteriormente". Portanto, o programador pensou que poderia haver alguma alteração nessa função posteriormente. Como você o acessa como uma função e não como o próprio parâmetro, você pode facilmente mudar isso globalmente. Digamos que você tenha um índice com:

function getIndex(index)
    return index
end

e como seu índice começa em 0, tudo bem. Mais tarde, você altera um componente em outro lugar, esse componente precisa que você traduza seu índice para começar em 1. Você teria que adicionar centenas de índice + 1 em qualquer lugar do seu código. Mas com um método como este, basta dizer:

 function getIndex(index)
    return index+1
end

e você está bem. Funções como essa podem levar rapidamente ao excesso de engenharia, mas em alguns momentos elas fazem muito sentido!

reggaemuffin
fonte
2
Sim, embora valha a pena notar que a doutrina da função publicada pelo OP não sugere que esse seja o objetivo da função no caso dele.
Mark Amery
6

Funções de stub como essa são comuns em situações de herança de tipo. A classe base pode não fazer nada útil, mas as classes derivadas podem fazer várias coisas com as entradas. Declarar a função stub na classe base permite que todas as classes derivadas tenham uma função com esse nome, e as classes derivadas individuais a substituam por algo mais elaborado e útil.

jackr
fonte
5

Um cenário adicional é semelhante ao uso em python e C # de propriedades, mas em idiomas que não possuem o recurso.

Em geral, você pode declarar algo como apenas um membro da classe; digamos, 'nome' como uma string. Isso significa que você acessa assim:

someobject.name

Mais tarde, você decide que o nome realmente precisa depender do que está no objeto. Portanto, deve ser realmente uma função. Opa! Mesmo sem argumentos, isso significa que todo o código que o acessa agora deve ser alterado para

someobject.name()

Mas se você tiver muitas instâncias dessa ligação, as chances de nada dar errado são muito baixas - em algum lugar em que essa alteração não será feita, o programa falhará quando você chegar a esse ponto etc.

As propriedades em C # / Python permitem substituir uma função pelo que costumava ser um atributo, enquanto ainda permitem que ela seja acessada como um atributo, ou seja, sem alterações. Você nem precisa ter planejado com antecedência.

Se o seu idioma não tem isso, você precisa planejar com antecedência, mas ainda pode apoiá-lo como as pessoas faziam antes, tornando-o uma função desde o início que não faz nada. No começo, isso não fará nada de interessante e parece que deve ser removido, e muitas funções desse tipo nunca são alteradas. Mas, mais tarde, se você perceber que, realmente, sempre que você ligar, Widget.wtrprecisará remover alguns caracteres especiais, isso não é grande coisa - já é uma função, basta adicionar isso e pronto.

TL; DR Esse poderia ser apenas um programador inteligente que planeja antecipadamente mudanças futuras.

Corley Brigman
fonte
3
Isso faria sentido se esse método dependesse de qualquer outra coisa, mas não. Não é uma propriedade, getter / setter ou um campo. É um método que atualmente não faz nada. A única maneira de ele planejar mudanças futuras é se a lógica desse método precisar mudar.
Matthew Steeples
1
Não precisa ... significa que, no momento, eu não processo esses dados, mas mais tarde, se eu quiser, todos os usuários desses dados obtêm os dados processados ​​gratuitamente. Exemplo estúpido: digamos que você imprima seqüências de caracteres na tela e costuma fazer isso print data. Então, mais tarde, você percebe que todas as seqüências de caracteres devem estar em maiúsculas - você teria que procurar todas as impressões do programa e mudar para print data.upper(). Mas se você tem def cdata(data): return datae em todo lugar diz print cdata(data), então você muda para def cdata(data): return data.upper()e é a única mudança.
precisa saber é o seguinte
Entendo o que você quer dizer aí. Isso faz mais sentido
Matthew Steeples
2

Não é inútil, na verdade, pode ser extremamente útil, pois torna seu código mais uniforme e flexível.

Digamos, por exemplo, que você tenha uma lista de pessoas e uma lista suspensa para o usuário selecionar se queremos ver "todos" ou apenas aqueles que são "masculinos" ou "femininos".

Você pode manipular "all" como um caso especial; nesse caso, será necessário um extra se e para verificar esse caso explicitamente, ou você pode ter uma função de filtro que apenas retorna seu parâmetro (por exemplo, permite que tudo passe), designado para ser usado para o caso "all".

Hejazzman
fonte
4
Isso não se encaixa no cenário. Eu quis dizer uma função que retorna seus parâmetros e, em nenhum caso, não faz mais nada.
Sempie
@Empie: é o que ele está dizendo. Se você tem uma Filterclasse ou interface com MaleFiltere FemaleFiltersubclasses, e seu código requer algum filtro, é como você lida com um filtro que não faz nada (retorna seu parâmetro inalterado) All. A função nunca faz nada, mas pode ser substituída por uma que faz.
Magus
@ Magus, mas no seu cenário a função é algum tipo de espaço reservado que será substituído posteriormente, ou simplesmente existe porque a função antiga ficou obsoleta, mas o programa precisa dessa passagem. Enfim, não é uma entrega. A função não atribui o parâmetro inalterado a outra função, como um filtro faria, mas retorna à função de chamada.
Sempie
@Empie Não, não é nem um espaço reservado, é um uso temporário. É uma noção útil de codificação (e matemática), a função "identidade". E, sim, ainda é uma transferência, se ela retorna para "outra função" ou para a função de chamada. A chave é que a função "identidade" pode ser uma das muitas funções possíveis chamadas pela função de chamada e é usada para evitar if e maiúsculas e minúsculas quando a função chamada não precisa fazer nada.
21417 Hejazzman