# Arrays in Version 2

Version 2 of AGK introduced some new features to arrays, in particular the ability to sort, insert, and pass by reference into functions.

## Array Declaration and Resizing

To maintain backwards compatibility arrays can still be defined with DIM, but version 2 introduces a new method of defining arrays that will become particularly important when defining them in types. Note that both DIM arrays and new style arrays perform exactly the same after they are declared so any functions mentioned here will also work on DIM arrays. The new method is mainly for consistency. The new method is as follows

    myArray as integer[5]

The keyword DIM is not used and the size is moved to the end of the declaration. Arrays declared like this can only be declared once, unlike DIM arrays which can be declared multiple times to resize the array. The prefered method of resizing an array is now:

    myArray.length = newSize

Where newSize can be any expression that could be assigned to a variable. An array length can also be discovered by using it as an expression like so

    print( myArray.length )

Note that because arrays start at index 0 and allow the size parameter as a valid index, an array defined as "DIM myArray[2]" or "myArray as integer[2]" would have 3 elements (0,1, and 2) but array.length will return "2" to reflect the size parameter that was used to declare it. Therefore an array of length 0 has one element and an empty array will return the length "-1".

For simplicity it may be beneficial to ignore index 0 at first, and assume that arrays start at index 1. This way the length parameter matches the number of assumed elements in the array and index 0 can be introduced as an additional element later. Some people used to use index 0 to store the length of the array for convenience, but with the new changes this is no longer necessary.

## Inserting and Removing

Elements can now be inserted and removed from arrays which will increase or decrease their size accordingly. For example

    myArray as integer[] // creates an empty array
    myArray.insert(5) // insert 5 at the end of the array
    myArray.insert(7) // array now has the elements 5,7
    print( myArray.length ) // will display "1" meaning it has two elements
    myArray.remove() // removes the 7
    myArray.remove() // removes the 5
    print( myArray.length ) // will display "-1" meaning the array is empty

If an array is declared with a size parameter then elements will be inserted after the last existing element, for example

    myArray as integer[5]
    myArray.insert(15) // array now has the elements 0,0,0,0,0,0,15
    print( myArray.length ) // will display "6" meaning it has seven elements
    myArray.remove() // removes the 15
    myArray.remove() // removes the last zero
    print( myArray.length ) // will display "4"

Elements can also be inserted at specific points in the array by adding an index parameter to the insert or remove command like so

    myArray as integer[4]
    myArray[0] = 10
    myArray[1] = 11
    myArray[2] = 12
    myArray[3] = 13
    myArray[4] = 14
    myArray.insert(15,2) // insert 15 at the second index of the array
    print ( myArray[2] ) // will print "15"
    // the array curently looks like this [10,11,15,12,13,14]
    myArray.remove(0) // removes the element at index 0
    // the array now looks like this [11,15,12,13,14]
    myArray.remove(3) // removes the element at index 3
    // the array now looks like this [11,15,12,14]

## Sorting and Searching

Arrays can now be sorted using the .sort() command and searched using the .find(item) command. For example

    myArray as integer[5] = [3,4,1,5,2,6]
    myArray.sort() // array is now [1,2,3,4,5,6]
    index = myArray.find(4) // will return "3" as array indexes start at 0

.sort() will always sort in ascending order and .find(item) will only work on arrays that are in ascending order. If .find(item) cannot find the item you are looking for it will return "-1". You can sort arrays of Integers, Float, Strings, and Types. When sorting types the first variable of the type will be used to compare elements.

    type myType
        ID as integer
        name as string
    endtype
    myArray as myType[3]
    myArray[0].ID = 5 : myArray[0].name = "Bob"
    myArray[1].ID = 4 : myArray[1].name = "Alice"
    myArray[2].ID = 1 : myArray[2].name = "Carol"
    myArray[3].ID = 2 : myArray[3].name = "David"
    myArray.sort()
    remstart
        the array now looks like this
        [0]: ID=1, name="Carol"
        [1]: ID=2, name="David"
        [2]: ID=4, name="Alice"
        [3]: ID=5, name="Bob"
    remend

There is also a special insert command named .insertsorted(item) that will insert into a sorted array and maintain the array's ascending order so it can still be searched. For example, taking the array above

    myItem as MyType
    myItem.ID = 3
    myItem.name = "Eve"
    myArray.insertsorted(myItem)
    remstart
        the array now looks like this
        [0]: ID=1, name="Carol"
        [1]: ID=2, name="David"
        [2]: ID=3, name="Eve"
        [3]: ID=4, name="Alice"
        [4]: ID=5, name="Bob"
    remend

## Misc

There are some additional array commands that don't fit in the above categories, they are .swap(index1,index2) to swap two elements in an array (including types and multidimenional arrays) and .reverse() to reverse the elements in an array.

## Arrays in Types

Arrays can now be defined in types like so

    type myType
        ID as integer
        mySubArray as integer[5]
    endtype
    myVar as myType
    myVar.mySubArray[0] = 6

The array could also be defined as an array of another type if desired so you can do things like this

    type myType1
        ID as integer
        mySubArray1 as integer[5]
    endtype
    type myType2
        name as string
        mySubArray2 as myType1[8]
    endtype
    myVar as myType2
    myVar.mySubArray2[0].mySubArray1[4] = 6
    // or
    myVar.mySubArray2[3].mySubArray1.sort()

## Passing by Reference

Previously only types could be passed into functions and they were passed by value, meaning the type would be copied into a new variable which was then deleted at the end of the function. Now types can be passed by reference meaning that the variable being passed in will be modified by any changes in the function. For example

    function func1( a as point ) // pass by value, variable is copied
        a.x = 5 // this change is local and lost at the end of the function
    endfunction
    function func2( a ref as point ) // pass by reference, variable is the original
        a.x = 7 // this change modifies the original variable
    endfunction
    type point
        x as float
        y as float
    endtype
    myVar as point
    myVar.x = 1
    myVar.y = 2
    func1( myVar ) // doesn't change the variable
    print( myVar.x ) // will print "1"
    func2( myVar ) // does change the variable
    print( myVar.x ) // will print "7"

The same can also now be done with arrays

    function func1( a as integer[] ) // pass by value, variable is copied
        a[0] = 5 // this change is local and lost at the end of the function
    endfunction
    function func2( a ref as integer[] ) // pass by reference, variable is the original
        a[0] = 7 // this change modifies the original variable
    endfunction
    myArray as integer[3]
    myArray[0] = 1
    myArray[1] = 2
    myArray[2] = 3
    myArray[3] = 4
    func1( myArray ) // doesn't change the variable
    print( myArray[0] ) // will print "1"
    func2( myArray ) // does change the variable
    print( myArray[0] ) // will print "7"

The new compiler is also very flexible about what you can pass into a function that takes a type or array, for example

    function func( a ref as integer[] ) // pass by reference
        a[0] = 7
    endfunction
    type myType
        ID as integer
        subArray as integer[5]
    endtype
    myVar as myType
    func( myVar.subArray ) // passes the array from the type into the function
    print( myVar.subArray[0] ) // will print "7"

To pass multidimensional arrays to functions use additional square brackets in the function declaration

    function func1( a ref as integer[] ) // accepts a single dimensional array
        a[0] = 6
    endfunction
    function func2( a ref as integer[][] ) // accepts a two dimensional array
        a[0,0] = 7
    endfunction
    function func3( a ref as integer[][][] ) // accepts a three dimensional array
        a[0,0,0] = 8
    endfunction

and so on up to six dimensions. You can also pass sub arrays of multidimensional arrays into functions like so (using the functions above)

    myArray as integer[5,10,15]
    func1( myArray[0,0] ) // passes the array at [0,0] to the function as a single dimensional array
    print( myArray[0,0,0] ) // will display "6"

Also note that in these cases "myArray.length" would return 5, "myArray[0].length" would return 10 and myArray[0,0].length" would return 15, and each dimension can be resized individually

    myArray[0,0].length = 20
    myArray[0,1].length = 30

## Assignment

Arrays can be assigned values using the square bracket notation like so

    myArray as integer[3]
    myArray = [1,2,3,4]
    myArray2 as integer[2,5]
    myArray2[0] = [1,2,3,4]
    myArray2[1] = [5,6,7,8]
    myArray2[2] = [9,10,11,12]

If the number of elements being assigned is greater than the current array length then the array will be expanded to accommodate the new elements. If the number of elements is less than the current array length then the array length will remain the same and new elements will overwrite the beginning of the array, whilst the rest of the array remains unchanged

Arrays and types can also now be assigned directly to each other, doing so will copy the contents of the array or type to the other variable

    myArray as integer[3]
    myArray2 as integer[5]
    myArray = [1,2,3,4]
    myArray2 = [11,12,13,14,15,16]
    myArray = myArray2 // myArray is now length 5 with copies of the values in myArray2
    print( myArray[4] ) // will display 15

Any sub arrays or sub types are also copied in their entirety, nothing will be shared with the new variable

    type myType
        ID as integer
        subArray as integer[5]
    endtype
    var1 as myType
    var2 as myType
    var1.subArray[1] = 5
    var2.subArray[1] = 10
    var1 = var2 // the type is copied along with the array it contains
    print( var1.subArray[1] ) // will print 10
    print( var2.subArray[1] ) // will print 10
    var2.subArray[1] = 15 // the array was copied so changes to one do not affect the other
    print( var1.subArray[1] ) // will print 10
    print( var2.subArray[1] ) // will print 15

## JSON

Arrays can be converted to and from JSON strings by using the .toJSON() and .fromJSON(string) commands like so

    MyArray as integer[5]
    MyArray = [10, 53, 2, 678, 3, 2]
    var1 as string
    var1 = MyArray.toJSON()
    var2 as string
    var2 = "[1,2,3,4,5]"
    MyArray.fromJSON( var2 )

When populating an array from a JSON string the array length will be adjusted to match the length of the array in the JSON string. You can also save and load the array to a JSON file by using the .save(filename) and .load(filename) commands like so

    MyArray.save( "MyArray.json" )
    MyArray.load( "MyArray.json" )

Types can also be converted to and from JSON strings like so

    type spritetype
    	ID as integer
    	x as float
    	y as float
    	width as float
    	height as float
    endtype
    MyType as spritetype
    MyType.fromJSON( '{"ID": 4, "x": 10.5, "y": 20, "width": 50.1, "height": 20.45}' )
    var1 as string
    var1 = MyType.toJSON()

Types can contain other types or arrays, and will produce correctly nested JSON objects and arrays to match. There is no limitation on the contents of a type or array when converting it to JSON. When converting a JSON array to an AGK array then the array must only contain one type of variable, for example all integers, all floats, or all strings. There is no limit on a JSON object when converting it to an AGK type.

If a JSON object contains fields that are not in the AGK type being used to load it, then those fields will be ignored. If the AGK type contains fields that are not specified in the JSON object then those fields will be set to zero.

If a JSON object contains field names that are keywords in AGK then they cannot be directly loaded into an AGK type, since it won't be able to use those keywords as variable names. To overcome this you can use an underscore in front of the variable name in the AGK type and it will match JSON fields that don't have the underscore. For example

    type spritetype
    	ID as integer
    	x as float
    	y as float
    	_type as integer
    endtype
    MyType as spritetype
    MyType.fromJSON( '{"ID": 4, "x": 10.5, "y": 20, "type": 5}' )
    Print( MyType._type ) // will print the number 5

When using .toJSON() on a type, any variables that start with an underscore will have that underscore removed in the JSON string, so in the example above the JSON string produced by .toJSON() will contain the field "type" rather than the field "_type". Only the first underscore is removed, so if you actually wanted the JSON field name to begin with an underscore then add two underscores to the AGK type variable instead, i.e "__type" in AGK would be converted to "_type" in JSON.