Paso de valores a una función: por valor o por referencia.
Siguiendo con el tema de las funciones y sus parámetros, quedó pendiente en la [entrada anterior] explicar el modo (los modos) en que podemos pasar datos de un script a una función (1).
Cuando usamos funciones debemos proporcionarlas información para que puedan cumplir su cometido. Ya vimos que esta información, que procede del script desde el que son llamadas, recibe el nombre de parámetro y se localiza en la definición de la misma función, entre el paréntesis que sigue al nombre (en pseudocódigo NombreFuncion (parametro1, parametro2...)). Pues bien, esa información puede ser pasada de dos formas: por valor o por referencia. Veamos las diferencias entre ambos.
- Paso por valor: Se crea una copia local de la variable dentro de la función.
- Paso por referencia: Se maneja directamente la variable, los cambios realizados dentro de la función le afectarán también fuera.
Tradicionalmente los datos simples (variables) se pasan por valor y los complejos (conjuntos de datos o matrices) por referencia.
En OOo Basic el modo en que por defecto se pasan los datos es por referencia, así estas dos expresiones son la misma: fNomFunc(paramAs String) -> fNomFunc(ByRef param As String). En este caso no se pasa una copia de la variable a la función, sino que se pasa una especia de enlace directo, por lo que cualquier cambio que se realice en la variable en la función o subrutina, se traslada al script (por ejemplo) desde la que se llamó a la función.
Al pasar la variable por valor (fNomFunc(ByVal param As String)) estamos pasando una copia de la variable a la función o subrutina, por lo que los cambios que se realicen sobre la variable dentro de la función o subrutina no se verá reflejado en el script (por ejemplo) que la llamó ya que son variables diferentes.
Por lo dicho, aunque es común que no especifiquemos el modo en que se pasan los valores entre script y funciones, por lo que excepcionalmente leeremos en la declaración de la función estas instrucciones (ByRef, ByVal). Cuando así sea (como digo, la mayoría de las veces) deberemos recordar que, posiblemente sin advertirlo, lo que estamos haciendo es pasar los valores por referencia.
Si así se hace es porque generalmente ese es el modo más "económico" de trabajar, pero explicitar el modo de paso de los valores ayuda a entender mejor el funcionamiento esperado en la función. Un ejemplo un tanto complejo, pero que aquí empleo únicamente a modo ilustrativo...
Function aAdd( ByRef a(), ByVal xValor )
Dim u As Longu = UBound( a ) + 1ReDim Preserve a( u )a(u) = xValor
aAdd = a
End Function
Esta [función] permite añadir un elemento a una matriz inicialmente vacía. Consta de dos parámetros, uno complejo (la matriz a()), pasado por referencia (y explicitado el modo de paso) y otro simple (la variable xValor), que también explicitamente se pasa por valor. Al hacerlo así, estamos pasando la matriz "original" del script que llama a la función y una copia que funcionará independientemente de la variable (2).
El resultado que obtenemos al usar esta función es que la matriz mRecurso() (argumento 1 asociado al parámetro a()) queda en el script (3) conformada con por los datos que cumplen el criterio que establecemos en el script mediante el condicional If...
If mFuente(i) > 20 Then
mRecurso() = aAdd(mRecurso(), mFuente(i))
End If
... el cual (el criterio) viene definido en función del argumento 2 (mFuente(i)), asociado por valor con el segundo parámetro (ByVal xValor ) pasado por valor.
Podrás comprobar que definir la matriz en estos términos (Function aAdd( ByRef a() As Integer, ByVal xValor As Integer) As Object) o en estos otros (Function aAdd(a(),xValor)) no modifica el funcionamiento de la función ni el resultado que obtenemos en el script (4), ni entre sí, ni respecto al modo en que definimos la función en el código primitivo. No obstante, ese y el modo extenso que expuse ahora nos informan claramente del modo en que opera la función, mientras que la expresión más simple lo oculta.
NOTAS
(1) Sigo aquí las explicaciones expuestas en [wiki.open-office.es] donde se proporciona una buena información sobre el tema. Muy recomendable.
(2) Recuerda que el orden en que se pasan los valores en la llamada realizada desde el script es fundamental para que la función (o la subrutina) funcionen correctamente, ya que es ese orden el que permite establecer la relación entre los argumentos y los parámetros. Ver al respecto [esta entrada]
(3) Este es el script completo. Aunque lo muestro por facilitar la comprensión del proceso no pretendo explicar ahora su lógica, por lo que sólo muestro la parte del código del script que puede ayudar a comprenderlo hasta el punto en que es necesario (en rojo el ciclo que contiene el condicional comentado en el texto de la entrada).
Sub MaticesDim mFuente() As Integer, mRecurso() As Integer, i As Integer'Creamos la matriz-origen (mFuente()) mediante Array()mFuente = Array(11,24,14,38,6,32,27,9,46)'Pasamos valores a la función aAdd() condicionado al cumplimiento de un criterio:'que el valor del elemento de la matriz-origen sea superior a 20For i = LBound(mFuente ()) To UBound(mFuente ())If mFuente(i) > 20 ThenmRecurso() = aAdd(mRecurso(), mFuente(i))End IfNextEnd Sub
(4) Quiero llamar la atención sobre la definición de lo que devuelve la función como Objeto (...() As Object), ya que se comprueba que eludir esa especificación no afecta al funcionamiento de la función, como se comprueba en la forma simple de enunciarla, pero hacerlo como de tipo Integer (que es lo que son en realidad los datos que devuelve), sí lo hace.
No hay comentarios:
Publicar un comentario
Comenta esta entrada