Array: Asignación vs Copia

Si estás comenzando a programar con Xojo probablemente este sea uno de los casos que puedan confundirte a la hora de crear tus propias aplicaciones en las que hagas uso de uno de los tipos de datos contenedores del lenguaje: Array.

Se trata de lo que esperas obtener cuando asignas los contenidos de un Array sobre otro… a lo que realmente obtienes cuando utilizas el operador de asignación (“=”).

Después de todo, con el siguiente fragmento de código podríamos esperar que los contenidos del Array accesible mediante la variable ATarget se correspondan con los valores accesibles mediante la variable ASource; y en principio así es. Prueba a escribir el siguiente código en cualquier evento o método creado por ti mismo en un proyecto de Xojo:

Dim ASource() As Integer = Array(1,2,3,4,5,6,7,8)
Dim ATarget() As Integer
ATarget = AFuente

Si a continuación estableces un punto de parada en la última línea de código y ejecutas la aplicación verás que, efectivamente, los contenidos del Array ATarget() se corresponden con lo que cabria esperar: aquellos proporcionados durante la asignación de la variable ASource().

Ahora bien, ¿qué ocurrirá si a continuación añadimos la siguiente línea de código al final de nuestro fragmento?:

Redim ASource(-1)

Con ella estaremos redimensionando la capacidad de nuestro Array ASource() a un total de 0 elementos. Es decir, en la práctica estaremos vaciando sus contenidos.

Como resultado de esta operación podrías esperar que, si bien los contenidos de ASource() se han vaciado, ATarget() continuará preservando los valores previamente asignados. ¿Verdad?

Lo cierto es que no es así.

Así funciona la asignación en los Array

Cuando se emplea el operador de asignación (=) para asignar los valores de un Array a otro, lo que ocurre en realidad es que el de destino (aquél que recibe los valores) contendrá referencias a los elementos almacenados en el utilizado como fuente de la operación, y no copias de dichos valores.

Por lo tanto, al tratarse de referencias, todas las operaciones que realicemos sobre el Array fuente se verán reflejadas en el de destino, ya se trate de tipos de datos primarios o bien de cualquier otro tipo de Objeto almacenado.

Si quieres verlo por ti mismo, prueba a eliminar el anterior punto de parada y situarlo en esta ocasión sobre la última línea de código.

Cuando ejecutes de nuevo el programa y utilices a continuación la opción del Depurador de Xojo para ejecutar la línea de código sobre la que has establecido el punto de parada, observarás como ahora tanto las variables ASource() como ATarget() indican que su dimensión de valores se corresponde con -1. Es decir, cuando vacías de cotenidos el Array fuente también lo hará el de destino.

¿Por qué ocurre esto?

Entender mejor Referencia vs Copia

Las aplicaciones que se ejecutan sobre un ordenador o cualquier dispositivo residen en la memoria, tanto el código que se ha de ejecutar como los objetos que creamos y utilizamos durante la ejecución del mismo.

Por ejemplo, cuando en nuestro código Xojo realizamos la declaración de una variable (en este caso un Array de tipo Integer, podemos pensar en dicha variable como en una simple etiqueta asociada con la posición inicial de la región en memoria que se utilizará para almacenar posteriormente los valores en dicho Array. De forma esquemática podríamos visualizarlo así:

De modo que cuando añadimos nuevos elementos sobre el Array podríamos representarlo visualmente de la siguiente forma; si bien la implementación real de como Xojo organiza los objetos almacenado por un Array puede variar sobre la mostrada. Es decir, no tiene por qué tratarse de posiciones de memoria contigua:

Ahora bien, cuando utilizamos el operador “=” para asignar los contenidos de nuestro Array ASource sobre el Array ATarget lo que ocurre en realidad es que el valor almacenado por ATarget se corresponderá con la primera posición de memoria utilizada por el Array ASource, explicando así que todas las operaciones realizadas sobre dicha región de memoria se reflejen no sólo en ASource sino también en ATarget (ambos apuntan a las mismas posiciones de memoria para el acceso a los elementos del Array):

Sin embargo, cuando iteramos sobre los elementos del Array ASource y utilizamos el método Append sobre el Array ATarget, lo que ocurrirá en este caso es que el Array de destino utilizará su propia región de memoria para guardar los valores añadidos y, por tanto, es independiente de la región de memoria utilizada por el Array fuente.

De este modo, las operaciones realizadas sobre los elementos apuntados por el contendor utilizado como fuente no se verán refleajos en el contendor de datos de destino:

Copia de elementos en los Array

Si lo que realmente deseamos es que nuestro Array de destino contenga su propia copia de los valores correspondientes al Array fuente, entonces el enfoque que tendremos que llevar a cabo es claramente diferente.

En vez de utilizar el operador de asignación, tendremos que iterar (acceder) a cada uno de los elementos contenidos en el Array fuente y añadirlos sobre el de destino.

Para ello utilizamos el método Append sobre el Array de destino, mientras que para acceder a cada uno de los valores del fuente emplearemos el acceso mediante índice utilizando la sintaxis habitual (por ejemplo, con Array(0) estaremos accediendo al primero de los elementos almacenados en dicho Array.

Sustituye el anterior código de ejemplo por el siguiente:

Dim Fuente() As Integer = Array(1,2,3,4,5,6,7,8)
Dim Max As Integer = Fuente.Ubound
For n As Integer = 0 to Max
Destino().Append Fuente(n)
Next
Redim Fuente(-1)

Si ahora estableces el punto de parada del Depurador en la última línea de código y ejecutas el programa de ejemplo observarás como, tras ejecutar la última línea, nuestro Array Destino() conserva en esta ocasión su propia copia de valores aunque hayamos redimensionado el Array fuente para que vacíe sus contenidos una vez que se ha redimensionado.

Si lo deseas, puedes ver la anterior explicación en el siguiente tutorial en vídeo:

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *