Collections

ListArrayList | ArrayOfHashTable | Set | Array

Overview

  • List references can point to ArrayList or LinkedList objects, among others.
  • ArrayList and HashTable (which is equivalent to HashMap in Java) are the most frequently used collection types.
  • A "String[]" reference is shorthand for a List<<String>> reference.
  • Creating a "String[]()" object is shortand for creating an "ArrayList<<String>>()" object.  Likewise "String[](5)" is equivalent to "ArrayList<<String>>(5)".
  • The line "local String[] names()" is shorthand for "local List<<String>> names = ArrayList<<String>>()".
  • "local HashTable<<String,Int32>> number_lookup()" creates a HashTable (lookup table) of Int32 values that use a String key to access.
  • Writing 'number_lookup["five"] = 5' is shorthand for 'number_lookup.set("five",5)'.
  • Writing 'println( number_lookup["five"] )' is shorthand for 'println( number_lookup.get("five") )'.

 

 

List<<DataType>>
underlying aspect : ListType, Readable<<DataType>>, IndexedData<<DataType>>
  • DESCRIPTION
    • A List aspect is an ordered collection that is Readable and addressable by index.
    • Numerical lists incorporate the ListArithmetic<<DataType>> aspect. Integer and Logical lists incorporate the ListBitwise<<DataType>> aspect.
  • PROPERTIES
    • modification_count : Int32
  • METHODS
    • count().Int32 : abstract
      • Returns the number of elements in this list. This will be zero or higher.
    • modification_count().Int32
      • Returns a counter representing the number of times items has been added to or removed. Used by readers to detect concurrent list modification errors. For example, when an inner method removes an item from a list the modification counter is incremented. An outer "forEach" loop will detect that the count is different from its original value and throw a ConcurrentListModification error.
    • capacity().Int32
      • This list can store *at least* 'capacity' elements before it automatically reorganizes its underlying data structures. ArrayList implementations return the number of unused array slots; LinkedList implementations return "count + 1" because their data structure always supports another element.
      • A lists's capacity should not be used as the condition for a loop since the capacity of some lists (e.g. LinkedLists) never actually changes.
    • ensure_capacity(Int32 desired_capacity)
      • Directs a list to prepare itself to hold a total of 'desired_capacity' elements. Proper use prevents ArrayLists from having to resize their data structures multiple times over the course of an operation.
    • ensure_count(Int32 num_items)
      • Increases the size of this list by enough null/zero items so that its count is at least 'num_items'.
      • Default implementation.
    • add(DataType value).DataType[]
      • Appends 'value' to the end of this list.
      • Returns a reference to this list for call-chaining, e.g.:
      •   list.add(3).add(4).add(5)
        
        

        Invariant:

          new.count == old.count + 1
          new.last is value
        
    • add(DataType value,Int32 after_index).DataType[]
      • Inserts 'value' after the given index.
      • Returns:
          A reference to this list for call-chaining.
        
        

        Requires:

          after_index >= -1 and after_index < count
        
        

        Invariant:

          new.count          == old.count + 1
          new[after_index+1] == value
        
    • add(Readable<<DataType>> source).DataType[]
      • Adds each item from the Readable source to this list.
      • Returns a reference to this list for call-chaining.
    • insert(DataType value[,Int32 before_index]).DataType[] : abstract
      • Inserts the given value into the list just before the given index.
      • Returns a reference to this list for call-chaining.
      • Requires:
          before_index >= 0 and before_index <= count
        
    • insert(IndexedData<<DataType>> seq[,Int32 before_index]).DataType[]
      • Inserts all the given values in front of 'before_index'. Elements at 'begin_index' and higher are logically shifted up by one.
      • Returns:
          A reference to this list for call chaining.
        
        

        Requires:

          0 <= before_index and before_index <= count
        
        

        Invariant:

          this[before_index]   = value
          this[before_index+seq.count] = old[before_index]
          count = old.count + seq.count
        

        naive default implementation

    • copy_from(Readable<<DataType>> source).DataType[]
      • Equivalent to:
          list.clear
          list.add( source )
        
    • transfer_from(DataType[] source).DataType[]
      • Equivalent to:
          list.clear
          list.add( source )
          source.clear
        
    • to_List().DataType[]
      • Satisifies the ListAdaptable aspect of the IndexedData aspect by returning this list with no modifications.
    • remove(Int32 index).DataType : abstract
      • Removes and returns the element at the given index. Elements above 'index' are each shifted down by one space.
      • Invariant:
          new.count = old.count - 1
          result == old[index]
          new[i] == old[i+1] for all index <= i <= new.count
        
    • remove(Int32 first,Int32 last).DataType[]
      • Removes and returns the elements in the specified range. See discard() for a variant that's optimal when you don't need the return value.
      • 'first' and 'last' are clipped to be a valid range.
      • Returns:
          The list of elements from old[first] through old[last].
        
        

        This default implementation is non-optimal.

    • remove(Range<<Int32>> range).DataType[]
      • Removes and returns the elements in the specified range. See discard() for a variant that's optimal when you don't need the return value.
      • Requires: range.is_contiguous_ascending
    • remove_first().DataType
      • Equivalent to:
          list.remove(0)
        
    • remove_last().DataType
      • Equivalent to:
          list.remove(list.count-1)
        
    • remove_value(DataType value).Logical
      • Removes the first occurrence of 'value' from the list.
      • Returns:
          "true" if an occurrence of 'value' was found
          and removed, or "false" if it was not found.
        
        

        Technical note: this method can't be named remove() because in an Int32[] list, remove(index) and remove(value) would have the same signature.

    • discard(Int32 first[,Int32 last])
      • Removes the elements in the specified range. Does not return the list of removed elements like remove() does. If only the 'first' parameter is given, elements from 'first' to the end of the list are discarded.
      • 'first' and 'last' are clipped to be a valid range.
      • This default implementation is non-optimal.
    • discard(Range<<Int32>> range)
      • Removes elements in the specified range.
      • Requires: range.is_contiguous_ascending
    • discard_first()
      • Removes the first element in the list without returning it.
      • This default implementation is non-optimal.
    • discard_last()
      • Removes the last element in the list without returning it.
    • discard_first(Int32 n)
      • Removes 'n' elements from the front of the list. Does not return the list of removed elements like remove() does.
      • This default implementation is non-optimal.
    • discard_last(Int32 n)
      • Removes 'n' elements from the end of the list. Does not return the list of removed elements like remove() does.
      • This default implementation is non-optimal.
    • clear()
      • Removes all the items in this list.
      • Invariant:
          new.count = 0
          new.capacity == old.capacity
        
        

        This default implementation is non-optimal

    • create_duplicate().DataType[]
      • Creates and returns a new list containing all the items in this list.
      • Called indirectly in response to: duplicate(list)
      • When used with references, note that this method does not duplicate the objects in the list but just the list data structure itself (a shallow copy).

 

ArrayList<<DataType>>
class : DataType[]
  • DESCRIPTION
    • The most common "collection" type in Slag, an ArrayList is an indexable list of items implemented using arrays.
    • An array list has 'count' and 'capacity'. Capacity is how many elements an arraylist can store before it has to create a larger backing array. Count is how many elements of the current array are currently in use. When 'count' reaches 'capacity', the next add() operation causes the backing array to be doubled in size.
    • An arraylist starts out at capacity 10, count 0 by default.
    • When you use "array notation" in Slag it creates arraylists. The following convenience conversions are performed:
    •   # Create an empty list with 10 capacity
        Int32[] nums(10)  # 10 capacity
          -> List<<Int32>> nums = ArrayList<<Int32>>(10)
      
        # Create a list of 10 zero/null values
        Int32[] nums = Int32[10]
          -> List<<Int32>> nums = ArrayList<<Int32>>( 10, 0 )
      
        # Create a list with the numbers 1 to 3
        Int32[] nums = { 1, 2, 3 }
          -> List<<Int32>> nums = ...
                 ArrayList<<Int32>>().add(1).add(2).add(3)
      
      

      Invariant:

        count >= 0
        capacity >= count
        data.count == capacity
      
  • PROPERTIES
    • data : Array<<DataType>>
      • The backing array for this arraylist.
    • count : Int32
      • The position to add the next item - also equivalent to the used item count.
  • METHODS
    • init()
      • Creates an empty arraylist of capacity 10.
    • init(Int32 initial_capacity)
      • Creates an empty arraylist with a specified initial capacity.
    • init(Int32 initial_capacity,DataType content)
      • Creates an array list full of 'initial_capacity' duplicates of the given 'content'.
    • init(Readable<<DataType>> readable)
      • Initializes this list to contain all the items from the 'readable' data source.
    • count().Int32
      • Returns how many values there are in this list.
    • capacity().Int32
      • Returns how many values this list can store before its backing array must be doubled in size.
    • ensure_capacity(Int32 min_capacity)
      • Effects that this list has a capacity of at least 'min_capacity'. If it has a lower capacity, the backing array is reallocated to have the necessary capacity.
    • ensure_count(Int32 num_items)
      • Increases the size of this list by enough null/zero items so that its count is at least 'num_items'.
    • get(Int32 index).DataType
      • Returns the element at the given zero-based index.
      • Requires:
          0 <= index and index < count
        

        Index may be within the bounds of the backing array but out of bounds for the arraylist.

    • set(Int32 index,DataType value)
      • Sets the element at the given zero-based index.
      • Requires:
          0 <= index and index < count
        

        Index may be within the bounds of the backing array but out of bounds for the arraylist.

    • add(DataType value).DataType[]
      • Adds the given 'value' to the end of this list.
      • Returns a reference to this list for call chaining.
      • Invariant:
          count = old.count + 1
          get[count-1] == value
        
    • insert(DataType value[,Int32 before_index]).DataType[]
      • Inserts the 'value' in front of 'before_index'. Elements at 'begin_index' and higher are shifted over by one.
      • Returns:
          A reference to this list for call chaining.
        
        

        Requires:

          0 <= before_index and before_index <= count
        
        

        Invariant:

          this[before_index]   = value
          this[before_index+1] = old[before_index]
          count = old.count + 1
        
    • insert(IndexedData<<DataType>> seq[,Int32 before_index]).DataType[]
      • Inserts all the given values in front of 'before_index'. Elements at 'begin_index' and higher are shifted over by one.
      • Returns:
          A reference to this list for call chaining.
        
        

        Requires:

          0 <= before_index and before_index <= count
        
        

        Invariant:

          this[before_index]   = value
          this[before_index+seq.count] = old[before_index]
          count = old.count + seq.count
        
    • remove(Int32 index).DataType
      • Removes and returns the element at position 'index'. All elements higher than 'index' are shifted down by one spot and the list count is decremented.
      • Returns:
          old[index]
        
        

        Requires:

          0 <= index and index < count
        
        

        Invariant:

          new[index] = old[index+1]
        
        
    • remove(Int32 first_index,Int32 last_index).DataType[]
      • Removes and returns the elements in the specified range.
      • 'first' and 'last' are clipped to be a valid range.
      • Returns:
          The list of elements from old[first] through old[last].
        
    • discard(Int32 first_index[,Int32 last_index])
      • Removes the elements in the specified range. Does not return the list of removed elements like remove() does. If only the 'first' parameter is given, elements from 'first' to the end of the list are discarded.
      • 'first' and 'last' are clipped to be a valid range.
    • discard_first()
      • Removes the first element in the list without returning it.
    • discard_last()
      • Removes the last element in the list without returning it.
    • discard_first(Int32 n)
      • Removes 'n' elements from the front of the list. Does not return the list of removed elements like remove() does.
    • discard_last(Int32 n)
      • Removes 'n' elements from the end of the list. Does not return the list of removed elements like remove() does.
    • trim_to_count().DataType[]
      • Resizes the backing array to exactly fit the values currently stored in this list. Only recommended when memory usage is a concern and you won't be adding additional elements in the near future.
      • Returns:
          A reference to this list for call chaining.
        
        

        Invariant:

          capacity == count
        
    • create_duplicate().DataType[]
      • Creates a duplicate of this list when the "duplicate(list)" command is given. If the list element type is a reference type, the new list contains a copy of the same references to the same objects - the objects themeselves are not duplicated.
      • Results:
          A duplicate list such that "all(this is result)" op== 
          true.
        
    • clear()
      • Removes all elements from this list. The capacity is unchanged.
      • Invariant:
          new.count == 0
          new.capacity == old.capacity
        

 

ArrayOf<<DataType>>
singleton class : Object
  • DESCRIPTION
    • Convenience class that allows you to use array-like notation to create single lists and multi-dimensional lists of lists that are internally structured like 1D, 2D or 3D arrays.
    • Example:
        local Int32[][] grid = ArrayOf<<Int32>>.create(3,5)
        grid[2][4] = 1
      
        local Real64[][] eye = ArrayOf<<Real64>>[5,5]
        forEach (i in 0..4) eye[i][i] = 1.0
      
        local String[] names = ArrayOf<<String>>[20]
        println( names.count )  # prints: 20
        println( names[0]    )  # prints: null
      
  • METHODS
    • create(Int32 dim1).DataType[]
      • Creates a list that contains 'dim1' number of "null" or "0" elements.
    • create(Int32 dim1,Int32 dim2).DataType[]
      • Creates a 2D list of lists that can be treated as a 2D array.
    • create(Int32 dim1,Int32 dim2,Int32 dim3).DataType[]
      • Creates a 3D list of lists of lists that can be treated as a 3D array.
    • get(Int32 dim1).DataType[]
      • Calls create(dim1).
    • get(Int32 dim1,Int32 dim2).DataType[]
      • Calls create(dim1,dim2).
    • get(Int32 dim1,Int32 dim2,Int32 dim3).DataType[]
      • Calls create(dim1,dim2,dim3).

 

HashTable<<KeyType,ValueType>>
class : LookupTable<<KeyType,ValueType>>
  • DESCRIPTION
    • Defines a lookup table that uses chained hashing (bins of linked lists) to associate key/value pairs. All the keys must be of the same datatype and all the values must be of the same datatype, but the keys can be different datatypes from the values.
    • The following requirements must be met for the following types to be used as KeyType:
    •   primitive (Int32, Real64, etc)
          No restrictions.
      
        compound
          You must define the following class method:
            Global::hash_code(CompoundType c).Int32
      
        reference
          You must override hash_code.Int32 in the class type.
          Class String already defines hash_code.
      
      

      See Object::hash_code() for more information on creating hash codes.

    • HashTable defaults to 16 bins with an average bin size of 3 - once the average number of entries per bin exceeds 3 the number of bins is doubled. Alternate values may be specified in the initializer.
    • Example:
        local HashTable<<String,Int32>> numbers()
        numbers[ "one" ]   = 1
        numbers[ "two" ]   = 2
        numbers[ "three" ] = 3
        ...
      
        local HashTable<<String,Int32>> factors()
        factors[ "hundred" ]  = 10^2
        factors[ "thousand" ] = 10^3
        factors[ "million" ]  = 10^6
        ...
      
        local String word_form = "two million"
        local String[] words = word_form.tidy.split
        println( numbers[words[0]] * factors[words[1]] )
          # prints: 2000000
      
  • PROPERTIES
    • bins : HashTableBin<<KeyType,ValueType>>[]
    • num_entries : Int32
    • average_bin_size : Real64
      • Limit of the average bin size. If there are 16 bins and an average_bin_size of 3, the table will expand once there are 3 items in each bin (3*16=48 items total, 48/16 bins=3 avg) or when a single bin has 48 items (48 / 16 = 3 avg). This value is used to calculate the max_entries before the table expands.
    • max_entries : Real64
      • Recalculated from average_bin_size each time the table expands.
    • max_bins : Int32
      • The number of bins (default: 512 ) at which the table will stop auto-expanding # and instead continue to fill the existing bins however large they may get.
    • hash_mask : Int32
      • Internal use. Set to the number of bins-1. E.g. for 16 bins the mask is 15, since hash_code & 15 -> 0..15
  • METHODS
    • init()
      • Default initializer, necessary if you ever make a singleton class that extends HashTable.
    • init(Int32 num_bins[,average_bin_size])
      • Initializes this hash table with the given number of bins (default 16) and the given average_bin_size (default 3.0).
    • clear()
      • Removes all mappings from this hash table.
    • count().Int32
      • Returns the number of mappings in this table.
    • set(KeyType key,ValueType value)
      • Associates the given value with the given key. When get() is called with 'key', 'value' will be returned.
    • set(Mapping<<KeyType,ValueType>> entry)
      • Associates the given value with the given key. When get() is called with 'key', 'value' will be returned.
    • get(KeyType key).ValueType
      • Retrieves the value (previously mapped with set()) associated with 'key'. Throws a NoSuchElementError if 'key' has not been defined.
    • find(KeyType key).Mapping<<KeyType,ValueType>>
      • Finds the underlying Mapping that defines the mapping between 'key' and 'value'. Returns a null reference if no mapping is present. Useful for optimizing conditional table operations.
      • Example without find():
          if (table.contains(id))
            person = table[id]
          endIf
        
        

        Example with find() - a bit faster:

          local var mapping = table.find(id)
          if (mapping isNot null)
            person = mapping.value
          endIf
        
    • contains(KeyType key).Logical
      • Returns "true" if 'key' has an associated value in this table that can be retrieved with get().
    • remove(KeyType key).ValueType
      • Removes the mapping between 'key' and its value from this table. Throws a NoSuchElementError if 'key' has not been defined.
    • get_bin(KeyType key).HashTableBin<<KeyType,ValueType>>
    • add(HashTable<<KeyType,ValueType>> other)
      • Adds all entries in the compatible hash table to this hash table.
    • expand_table()
      • Resizes this hash table to have double the number of bins as before.
    • to_String().String
      • Returns a string representation of this hashtable.
    • keys().HashTableKeyReader<<KeyType,ValueType>>
      • Returns a reader that iterates through this hash table's keys. These are not guaranteed to be an any particular order.
      • Example:
          local HashTable<<String,Int32>> ages()
          ages["Abe"] = 34
          ages["Murphy"] = 30
          ages["Matt"] = 28
          forEach (name in ages.keys)
            println( "$ is $ years old." (name,ages[name]) )
              # prints:
              #  Abe is 34 years old.
              #  Matt is 28 years old.
              #  Murphy is 30 years old.
          endForEach
        
    • values().HashTableValueReader<<KeyType,ValueType>>
      • Returns a reader that iterates through this hash table's values. These are not guaranteed to be an any particular order.

 

Set<<DataType>>
class : Readable<<DataType>>
  • DESCRIPTION
    • Models a set of unique items stored in no particular order.
  • PROPERTIES
    • data : HashTable<<DataType,Null>>
  • METHODS
    • init()
      • Default initializer.
    • add(DataType value).DataType
      • If the value is already in the set then returns the original value (which may be an equivalent although different object). Otherwise adds and returns 'value' to this set.
    • add(Set<<DataType>> other)
      • Adds all values in 'other' to this set.
    • contains(DataType value).Logical
      • Returns 'true' if this set contains the given value.
    • remove(DataType value)
      • Removes 'value' from this set. If the value is not in the set then a NoSuchElementError is thrown.
    • remove(Set<<DataType>> other)
      • Removes every value in 'other' from this set.
    • intersect(Set<<DataType>> other)
      • Removes all values in this set that are not in the other set.
    • count().Int32
      • Returns the number of items in this set.
    • create_reader().Reader<<DataType>>
      • Returns a reader that iterates through the values in this set. These are not guaranteed to be an any particular order.
    • to_String().String
      • Returns a string representation of this set.

 

Array<<DataType>>
class : ArrayType, Readable<<DataType>>, IndexedData<<DataType>>
  • DESCRIPTION
    • Primarily for internal use - in most cases use ArrayList instead.
    • Array is a placeholder type. Arrays are actually implemented in the runtime implementation; calls to array methods are intercepted by the program loader and translated into array-related opcodes.
    • The exception to this is when a call is made to an array using a reference of aspect types Readable or IndexedData - the loader is unable to intercept. However, the Slag-side implementation of each array simply calls itself, and *that* call *is* intercepted by the compiler.
    • To get an array in Slag you must be explicit, e.g. "Array<<Int32>>(20)". Convenience notation (such as Array[20]) generates ArrayLists instead.
    • Arrays are not covariant as they are in Java. An Array<<String>> counts as an Object but not as an Array<<Object>>.
    • Arrays may be extended or augmented but no new object properties may be added.
  • METHODS
    • init(Int32 size)
      • Sets up this array to contain the given number of elements.
    • count().Int32
      • Returns the count of how many elements are in this array.
    • get(Int32 index).DataType
      • Retieves the element at the zero-based 'index'.
      • Requires:
          0 <= index < count
        
    • set(Int32 index,DataType value)
      • Sets the element at the zero-based 'index' to the new 'value'.
      • Requires:
          0 <= index < count
        
    • create_duplicate().Array<<DataType>>
      • Creates a duplicate of this array when the "duplicate(array)" command is given. If the array element type is a reference type, the new array contains a copy of the same references to the same objects - the objects themeselves are not duplicated.