La función solo devuelve el parámetro sin cambios, ¿inútil?

15

Acabo de encontrar esta función en el proyecto en el que estoy trabajando:

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

Demasiado triste, el codificador ya no trabaja en la empresa. ¿Por qué uno haría una función que no hace nada, pero devuelve el parámetro con el que se llama?

¿Hay algún uso de dicha función, no especificado en este ejemplo, pero en general en cualquier caso?

Debido a

function aFunction(parameter)
    return parameter
end

Termina en

aFunction(parameter) == parameter

¿Por qué escribiría algo como

aFunction(parameter) == whatIWantToCheck

en lugar de

parameter == whatIWantToCheck

?

Sempie
fuente
posible duplicado del estilo
mosquito
13
@gnat ¿Cómo es eso un duplicado?
Kilian Foth
13
¿Eh? Esta función devuelve su parámetro: el encadenamiento implica el retorno this.
Kilian Foth
11
@gnat La pregunta es por qué alguien alguna vez escribiría una función que no hace nada más que devolverse. Sí, puede devolver ciertos objetos o valores para permitir el encadenamiento de métodos, pero esa no es su pregunta. Su pregunta es por qué alguien alguna vez escribiría algo como int getParam(int param) { //DO NOTHING return param; } Desde una perspectiva de encadenamiento de métodos, es una llamada completamente redundante e innecesaria, ya que puede dejar la función del OP fuera de una cadena de métodos y no haría una sola diferencia.
ZeroStatic
44
Esto probablemente no sea un tema y no se aplica a lua, pero hay un caso de uso válido para esto en PHP: en versiones anteriores, new Foo()->method();no era una sintaxis válida y function with($what) { return $what; }; with(new Foo())->method();se usaban construcciones similares como solución alternativa.
DCoder

Respuestas:

57

Su pregunta es como preguntar cuál es el bien del número cero si cada vez que lo agrega a algo obtiene el mismo valor. Una función de identidad es como el cero para funciones. Un poco inútil por sí mismo, pero ocasionalmente útil como parte de una expresión que utiliza funciones de orden superior, donde puede tomar una función como parámetro o devolverla como resultado. Es por eso que la mayoría de los lenguajes de programación funcionales tienen una ido identityen su biblioteca estándar.

Dicho de otra manera, tiene una práctica función predeterminada. Al igual que es posible que desee establecer offset = 0como un entero predeterminado, aunque eso haga que un desplazamiento no haga nada, puede ser útil poder establecerlo filterFunction = identitycomo una función predeterminada, aunque eso haga que el filtro no haga nada.

Karl Bielefeldt
fuente
¿No debería una función de filtro devolver un valor booleano? En este caso, la función de filtro "cero" sería la que devuelve verdadero.
Kirill Rakhman
1
@cypressious Una función de mapa, entonces.
sapi
66
O para pegarlo bajo un concepto de diseño: patrón de objeto nulo , edición de funciones
blgt
@cypressious, eso sería para un predicado que se pasa como argumento a una filterfunción de orden superior. Una función de primer orden filtertiene el tipo [a] -> [a],
Karl Bielefeldt
Por ejemplo, en C #, uso a menudo.OrderBy(x => x)
CodesInChaos el
27

Seguro. Imagine una API externa que le permita recuperar cosas de un lugar absolutamente necesario, pero debe especificar criterios de filtro y formateadores de salida para cada consulta, incluso si desea todos los resultados y desea obtenerlos exactamente como están almacenados.

Entonces tendrías que inventar una función trivial de "aceptar todo" y una función trivial de "devolver sin cambios" para obtener los datos. wtres precisamente un pseudoformateador tan trivial. Si usa mucho esa API, puede ser muy útil tener esta función de pseudo-ayudante en lugar de tener que crear una función anónima cada vez que consulta algo. (Puede considerar llamarlo en identitylugar de hacerlo wtrpara que quede claro de inmediato que no hace nada).

Kilian Foth
fuente
Realmente aún no entendía el sentido, pero ese es exactamente el escenario. Después de un tiempo, podría entender que trabajar en este proyecto teniendo en cuenta su respuesta, creo. atm me parece inútil, ... si obtuve los datos en bruto, ¿por qué querría una función para volver a darme los datos en bruto? ...
Sempie
3
@Sempie Nuevamente, si la API requiere una función de formateo, la única forma de obtener el texto inalterado es si la función no hace nada al texto.
Doval
3
En otras palabras: si tiene una función que requiere que se pasen los argumentos de filtro / formato, y no puede usarla nullcomo argumento, use una función de filtro vacía que filtre con 'nada' para que el programa deje de quejarse.
ZeroStatic
3
@Sempie Has trabajado con SQL, ¿verdad? ¿Sabes cómo puedes incluir o no incluir una WHEREcláusula? Eso es una cuestión de azúcar sintáctica. Esencialmente, la ausencia de una WHEREcláusula es exactamente la misma que si tuviera una WHEREcláusula que simplemente sigue adelante y permite todo. El hecho de que los diseñadores de SQL no le permitan especificar una WHEREcláusula, en lugar de obligarlo a dejar una, incluso cuando acepta todo, es más o menos azúcar sintáctica, y simplemente le han brindado esa opción para mayor comodidad. ..
Panzercrisis
55
Vale la pena señalar que, en muchos casos, es más rápido y más limpio tener un código que llame incondicionalmente a un método virtual o delegado que pueda o no hacer algo útil, que hacer que el código determine si la llamada es necesaria y omitirla si no.
supercat
15

¿No es eso solo un polimorfismo?

Desde mi experiencia con Qt tr() y wtr()se supone que los métodos deben usarse (allí, en Qt ) en la localización del Widgettexto de.

Por lo tanto, mediante la devolución de texto sin cambios este método se limita a decir: Widget does no localization (translation of the text) by default. Override this function to enable your own logic.

GreenScape
fuente
1
no me di cuenta de que esto era una cuestión de QT, obviamente esta es la respuesta.
Corley Brigman
8

Un caso muy común para esto es la "funcionalidad añadida más tarde". Entonces el programador pensó que podría haber algún cambio en esa función más adelante. Dado que accede a él como una función y no como el parámetro en sí mismo, puede cambiarlo globalmente fácilmente. Digamos que tiene un índice con:

function getIndex(index)
    return index
end

y como su índice comienza en 0, todo está bien. Más tarde, cambia un componente en otro lugar, este componente necesita traducir su índice para comenzar en 1. Tendría que agregar cientos de índice + 1 en todas partes en su código. Pero con un método como este, simplemente diga:

 function getIndex(index)
    return index+1
end

Y estás bien. Funciones como esta pueden conducir rápidamente a una ingeniería excesiva, pero en algunos puntos tienen mucho sentido.

reggaemuffin
fuente
2
Sí, aunque vale la pena señalar que la cadena de documentación de la función publicada por el OP no sugiere que este sea el propósito de la función en su caso.
Mark Amery
6

Las funciones de código auxiliar como este son comunes en situaciones de herencia de tipos. La clase base puede no hacer nada útil, pero las clases derivadas pueden hacer varias cosas con las entradas. La declaración de la función stub en la clase base permite que todas las clases derivadas tengan una función de ese nombre, y las clases derivadas individuales la anulan con algo más elaborado y útil.

jackr
fuente
5

Un escenario adicional es similar al uso en Python y C # de propiedades, pero en lenguajes que no tienen la característica.

En general, puede declarar algo solo como un miembro de la clase; digamos 'nombre' como una cadena. Esto significa que tiene acceso de esta manera:

someobject.name

Más tarde, decide que el nombre realmente debe depender de lo que hay en el objeto. Por lo tanto, realmente debería ser una función. ¡Uy! Incluso sin argumentos, eso significa que todo el código que accede ahora debe cambiarse a

someobject.name()

Pero si tiene muchas instancias de esta llamada, las posibilidades de que nada salga mal son bastante bajas: en algún lugar este cambio no se realizará, el programa se bloqueará cuando llegue a ese punto, etc.

Las propiedades en C # / Python le permiten sustituir una función por lo que solía ser un atributo, al tiempo que le permite acceder como un atributo, es decir, sin cambios. Ni siquiera tiene que haber planeado con anticipación.

Si su idioma no tiene eso, tiene que planificar con anticipación, pero aún puede apoyarlo de la manera en que la gente lo hacía antes al convertirlo en una función desde el principio que no haga nada. Al principio, no hará nada interesante, y parece que debería eliminarse, y muchas funciones de este tipo nunca cambian. Pero más tarde, si te das cuenta de que realmente cada vez que llamas Widget.wtrnecesitas eliminar algunos caracteres especiales, no es gran cosa, ya es una función, solo tienes que agregar eso y listo.

TL; DR Esto podría ser un programador inteligente que planifica con anticipación para futuros cambios.

Corley Brigman
fuente
3
Eso tendría sentido si este método dependiera de otra cosa, pero no es así. No es una propiedad, getter / setter o un campo. Es un método que actualmente no hace nada. La única forma en que planea futuros cambios es si la lógica de este método va a tener que cambiar.
Matthew Steeples
1
No tiene que ... significa que en este momento no proceso estos datos, pero más adelante, si quiero procesarlos, cada usuario de esos datos obtiene los datos procesados ​​de forma gratuita. Ejemplo estúpido: digamos que imprime cadenas en la pantalla, y generalmente lo hace print data. Luego, más tarde, te das cuenta de que todas las cadenas tienen que estar en mayúsculas: tendrías que buscar cada impresión en tu programa y cambiar a print data.upper(). Pero si tiene def cdata(data): return datay dice en todas partes print cdata(data), entonces simplemente cambia def cdata(data): return data.upper()y es el único cambio.
Corley Brigman
Ya veo lo que quieres decir allí. Eso tiene más sentido
Matthew Steeples
2

No es inútil, en realidad puede ser extremadamente útil, porque hace que su código sea más uniforme y flexible.

Digamos, por ejemplo, que tiene una lista de personas y un menú desplegable para que el usuario seleccione si queremos ver "todos" o solo aquellos que son "masculinos" o "femeninos".

Puede manejar "todos" como un caso especial, en cuyo caso necesitará un if adicional para verificar este caso explícitamente, o puede tener una función de filtro que solo devuelva su parámetro (por ejemplo, permite que todo pase), asignado para ser utilizado para el caso "todos".

Hejazzman
fuente
44
Eso no se ajusta al escenario. Me refería a una función que devuelve sus parámetros y, en ningún caso, no hace nada más.
Sempie
@Sempie: Eso es lo que está diciendo. Si tiene una Filterclase o interfaz con MaleFiltery FemaleFiltersubclases, y su código requiere algún filtro, un filtro que no hace nada (devuelve su parámetro sin cambios) es la forma en que maneja All. La función nunca hace nada, pero puede sustituirse por una que sí lo haga.
Magus
@Magus, pero en su escenario, la función es algún tipo de marcador de posición que será reemplazado más tarde o simplemente existe porque la función anterior se volvió obsoleta pero el programa necesita este paso. De todos modos, no es una entrega. La función no proporciona el parámetro sin cambios a otra función, como lo haría un filtro, sino que lo devuelve a la función de llamada.
Sempie
@Sempie No, no es un marcador de posición ni se usa como un paso temporal. Es una noción útil de codificación (y matemática), la función de "identidad". Y sí, todavía es un traspaso, ya sea que lo devuelva a "otra función" o a la función de llamada. La clave es que la función de "identidad" puede ser una de las muchas funciones posibles llamadas por la función de llamada, y se utiliza para evitar si y una carcasa especial cuando la función llamada no necesita hacer nada.
Hejazzman