Si estás comenzando a programar con Xojo, entonces probablemente te encuentres tarde o temprano en una situación en la que necesites utilizar uno de los diferentes tipos de Contenedores de datos disponibles: los Array. A diferencia de una variable “simple”, las declaradas como Arrays de datos permiten asignar múltiples valores (colección) disponibles bajo una misma declaración de variable, y acceder a ellas mediante el uso de un índice (la posición del valor dentro del Array).
Ahora bien, uno de los errores más comunes y que probablemente te confundan cuando empiezas es por qué no obtienes los valores esperados cuando asignas los contenidos de un Array fuente a otro Array de destino utilizando para ello el operador de asignación (el caracter “=”).
Después de todo, cuando utilizas un fragmento de código similar al siguiente podrías esperar (erróneamente) que los contenidos almacenados en el Array denominado ATarget fuesen los mismos que los almacenados en el Array denominado “ASource”. Por supuesto, y a primera vista, este es el caso. Prueba a escribir el siguiente fragmento de código en el Evento “Opening” de un nuevo proyecto Xojo o Método creado por ti mismo (no olvides incluir una llamada al método creado desde el evento Opening, en el caso de que decidas tomar esa ruta):
Var ASource() As Integer = Array(1,2,3,4,5,6,7,8)
Var ATarget() As Integer
ATarget = ASource
Si defines un punto de parada en la última línea de código y ejecutas tu aplicación de prueba, entonces verás que, tal y como esperas, los contenidos del Array ATarget() son los mismos que los contenidos almacenados por el Array ASource(). Navega por el Inspector del panel Depurador para ver el contenido de dichas variables.
Sin embargo, ¿qué ocurre si se añade la siguiente línea de código al final de nuestro anterior fragmento de código?:
ASource.ResizeTo(-1)
En este caso estaríamos cambiando el tamaño de la cantidad de elementos que puede contener nuestro Array ASource(); es decir, se eliminan todos los valores que, hasta ese momento, estuviesen almacenados.
Como resultado de esta operación podrías esperar que, si bien los contenidos de la variable ASource() se han vaciado, tu Array ATarget() continuará almacenando sus elementos.
Lo cierto es que no.
Así funciona la Asignación en los Array
Cuando utilizamos el operador de asignación (=) para definir los valores (elementos) de un Array a otro Array, lo que ocurre en realidad es que el Array de destino sólo almacenará una referencia al Array fuente (la variable situada a la derecha del operador de asignación), y por tanto no se almacena una copia de los valores u objetos almacenados.
Por tanto, y dado que estos valores son referencias, todas las operaciones que apliquemos al Array fuente se verán reflejadas en el Array de destino (y viceversa).
Si quieres comprobarlo por tu mismo, prueba a borrar el anterior punto de parada y crea un nuevo punto de parada en la última línea de código añadida.
Cuando ejecutes el código modificado, utilizando para ello la característica de Depuración del IDE de Xojo para que ejecute la última línea de código cuando este se ha detenido, verás como ambas variables de Array (ASource y ATarget) indican que sus dimensiones (capacidad actual para el almacenamiento de elementos) están indicadas como -1. Esto es: cuando borras el Array fuente aplicando el método ResizeTo, dicho cambio también se aplica en el Array de destino.
¿Por qué ocurre esto? Referencia vs. Copia
Todas las aplicaciones que se ejecutan en tu ordenador o cualquier otro dispositivo se almacenan en memoria, tanto el código a ejecutar como los objetos creados y utilizados durante todo el tiempo de vida de la aplicación.
Por ejemplo, cuando declaramos una variable en nuestro código de ejemplo (en este caso un Array de tipo Integer —números enteros—), podemos pensar en dicha variable como en una simple etiqueta que apunta a la primera posición de memoria sobre la cuál se almacenarán los valores posteriormente. Podemos representarlo de forma visual de la siguiente manera:
Por tanto, esta podría ser la representación visual de la memoria cuando añadimos nuevos ítems al Array, aunque en la implementación real de Xojo de los valores almacenados en un Array puede diferir de ella. No tiene por qué ser una región de memoria contigua o incluso utilizar la misma estructura a la hora de representar un Array en memoria:
Sin embargo, cuando utilizamos el operador de asignación (“=”) para definir los contenidos de nuestro Array ASource() en el array ATarget() lo que ocurre es que el conjunto de valores para la variable ATarget() está en la misma posición de memoria que el utilizado por la variable ASource(); de modo que todas las operaciones realizadas sobre el objeto ASource() —es decir, la región de memoria— también se verán reflejados en ATarget():
Por el contrario, cuando iteramos sobre los elementos almacenados en el Array ASource() y utilizamos el método Add en el Array ATarget(), lo que ocurre es que el Array de destino obtendrá y utilizará su propia región de memoria para almacenar su propia copia de los valores añadidos y, por tanto, es independiente de la región de memoria utilizada por el Array fuente.
De este modo, todas las operaciones realizadas sobre los elementos apuntados por el Array fuente no se reflejarán en el array de destino:
Copiando Elementos de un Array
Por tanto, si lo que queremos realmente es que nuestro Array de destino almacene su propia copia de los valores a partir de los encontrados en el Array fuente, todo lo que tendremos que hacer será cambiar el uso del operador de asignación por el de una iteración de todos los elementos del array fuente, añadiéndolos a continuación al Array de destino.
Para ello tenemos que utilizar el método Add en el Array de destino, mientras que para acceder a cada uno de los elementos almacenados en el Array fuente, tendremos que utilizar el índice de posición (por ejemplo ASource(0) accederá al primer elemento almacenado en dicho Array), mientras que ASource.LastIndex nos indicará, como un valor entero, la última posición de índice disponible en el Array, mientras que el método Count nos proporcionará la cantidad total de elementos almacenados en el Array (este valor siempre será el de LastIndex + 1, puesto que el primer índice tiene el valor 0).
Sustituye el anterior fragmento de código por este:
Var ASource() As Integer = Array(1,2,3,4,5,6,7,8)
Var ATarget() As Integer
Var Max As Integer = ASource.LastIndex
For n As Integer = 0 to Max
ATarget().Add ASource(n)
Next
ASource.ResizeTo(-1)
Ahora, si pones un punto de parada de depuración en la última línea de código y ejecutas la aplicación, entonces verás que tras ejecutar la última línea de código el Array ASource() mantendrá su propio conjunto de valores, incluso después de que hayamos redimensionado el Array fuente, ASource(), con el equivalente a “Array vacío o sin elementos”, borrando por tanto la región de memoria utilizada por los valores que hubiese contenido hasta ese momento dicha variable.