¿Existen argumentos objetivos y compatibles de ingeniería de software a favor o en contra de modificar los valores de los parámetros de sub-valor en el cuerpo de una función?
Una disputa recurrente (principalmente en buena diversión) en mi equipo es si los parámetros pasados por valor deben modificarse o no. Un par de miembros del equipo están convencidos de que nunca se deben asignar parámetros, por lo que el valor que se pasó originalmente a la función siempre se puede consultar. No estoy de acuerdo y sostengo que los parámetros no son más que variables locales inicializadas por la sintaxis de llamar al método; si el valor original de un parámetro por valor es importante, entonces se puede declarar una variable local para almacenar explícitamente este valor. No estoy seguro de que ninguno de nosotros tenga un muy buen apoyo para nuestra posición.
¿Es este un conflicto religioso que no se puede resolver, o hay buenas razones objetivas de ingeniería de software en cualquier dirección?
Nota: La cuestión de principio permanece independientemente de los detalles de implementación del lenguaje particular. En JavaScript, por ejemplo, donde la lista de argumentos es siempre dinámica, los parámetros pueden considerarse como azúcar sintáctica para la inicialización de variables locales desde el arguments
objeto. Aun así, uno podría tratar los identificadores declarados por parámetros como "especiales" porque aún capturan el paso de información de la persona que llama a la persona que llama.
fuente
Respuestas:
Adopto una tercera posición: los parámetros son como las variables locales: ambos deben ser tratados como inmutables por defecto. Por lo tanto, las variables se asignan una vez y luego solo se leen, no se modifican. En el caso de los bucles,
for each (x in ...)
la variable es inmutable dentro del contexto de cada iteración. Las razones para esto son:Frente a un método con un montón de variables que se asignan y luego no cambian, puedo concentrarme en leer el código, en lugar de tratar de recordar el valor actual de cada una de esas variables.
Frente al mismo método, esta vez con menos variables, pero ese valor cambia todo el tiempo, ahora tengo que recordar el estado actual de esas variables, así como trabajar en lo que está haciendo el código.
En mi experiencia, lo primero es mucho más fácil para mi pobre cerebro. Es posible que otras personas más inteligentes que yo no tengan este problema, pero me ayudan.
En cuanto al otro punto:
versus
Ejemplos contribuidos, pero en mi opinión, es mucho más claro lo que está sucediendo en el segundo ejemplo debido a los nombres de las variables: transmiten mucha más información al lector que esa masa
r
en el primer ejemplo.fuente
for
bucles con variables inmutables. ¿Encapsular la variable en la función no es suficiente para ti? Si tiene problemas para seguir sus variables en una mera función, quizás sus funciones sean demasiado largas.for (const auto thing : things)
es un bucle for, y la variable que introduce es (localmente) inmutable.for i, thing in enumerate(things):
tampoco muta a ningún lugareñoEso es algo que realmente me gusta de C ++ (bien escrito): puedes ver qué esperar.
const string& x1
es una referencia constante,string x2
es una copia yconst string x3
es una copia constante. Yo sé lo que sucederá en la función.x2
será cambiado, porque si no fuera así, no habría razón para hacerlo no constante.Entonces, si tiene un idioma que lo permite , declare lo que está a punto de hacer con los parámetros. Esa debería ser la mejor opción para todos los involucrados.
Si su idioma no permite esto, me temo que no hay una solución de bala de plata. Ambos es posible. La única pauta es el principio de menor sorpresa. Tome un enfoque y continúe con él en toda su base de código, no lo mezcle.
fuente
int f(const T x)
yint f(T x)
solo son diferentes en el cuerpo de la función.const int x
simplemente para aclarar x no se cambia por dentro? A mí me parece un estilo muy extraño.const
eliminará de la lista de parámetros si esto lo obstaculiza. Entonces no creo que esto responda la pregunta.Sí, es un "conflicto religioso", excepto que Dios no lee los programas (hasta donde yo sé), por lo que se reduce a un conflicto de legibilidad que se convierte en una cuestión de juicio personal. Y ciertamente lo he hecho, y lo he visto hecho, en ambos sentidos. Por ejemplo,
Entonces aquí, solo por el nombre del argumento t0 , probablemente elegiría no cambiar su valor. Pero supongamos, en cambio, que simplemente cambiamos el nombre de ese argumento a tNow , o algo así. Entonces me había olvidado de una copia local y escribí tNow + = dt; por esa última declaración.
Pero, por el contrario, supongamos que sabía que el cliente para el que se escribió el programa está a punto de contratar a algunos programadores nuevos con muy poca experiencia, que leerían y trabajarían en ese código. Entonces probablemente me preocuparía confundirlos con el paso por valor versus la referencia, mientras que sus mentes están 100% ocupadas tratando de digerir toda la lógica comercial. Entonces, en este tipo de casos, siempre declararía una copia local de cualquier argumento que se cambie, independientemente de si es más o menos legible para mí.
Las respuestas a este tipo de preguntas de estilo surgen con experiencia y rara vez tienen una respuesta religiosa canónica. Cualquiera que piense que hay una respuesta única (y que él lo sabe :) probablemente necesite algo más de experiencia.
fuente