April 23, 2019

Learn Nim - Collections

Just a continuation of the Learn Nim series that I’m jotting down while going through self studying Nim.

So let’s talk about collections now, you know, arrays and the sort.

Arrays

Arrays in Nim is similar to C, wherein all the data is saved in the stack. This is unlike languages like Java where arrays are stored in the heap.

What this means is that Arrays:

  • have an initial size
  • are not resize-able
  • are initialized with their default values if not set (for integers, 0. For strings, “”, etc.)
  • indexes can be negative values

Examples:

# different ways to create an array

var list: array[3, int] # create an array with index 0 to 2
assert list[0] == 0 # array members that are not "initialized" are set with their default values

var list2 = ["or", "you", "can", "do", "this"]

# you cannot mix datatypes in an array.
var list3 = ["this", "would", "not", "compile", 1]

# oh, and you can define arrays with custom ranges
var list4: array[-10 .. -1, int]

I honestly do not yet know any use-case for negative value indexes.

Iterating through an array can be done in a for loop

for item in list:
  echo item
  
# or you can also get the index
for idx, item in list:
  echo $idx & " - " & $item # we append the $ sign to convert integers to strings (ie. toString)
  
# you can also use high low
for idx in list.low .. list.high:
  echo list[idx]

Accessing an invalid index would cause the compiler to complain

var list: array[3, int]

list[500] = 1 # boo

So that’s that. How about an array that could be resized? Nim got that too, it’s called a sequence.

Sequences

Similar to arrays, but is resize-able. As you might have guessed, Sequences uses the heap instead of the stack, which is why we’re able to resize it. But like arrays, you cannot have different datatypes in a sequence.

let list: seq[int] = @[]
list.add(1)
list.add(2)

# you could also specify the initial size of the sequence
let list2 = newSeq[string](3) # newSeq is part of the standard system module

assert list2[0] == "" # as with arrays, they are automatically initialized with their default values

list2.add("a")
echo list2[3] # would output "a". This means that `add`ing entries to a sequence are added ontop of the current sequence length

As with arrays, you can iterate through the sequence using a for loop

let list: seq[int] = @[1,2,3,4]
for item in list:
  echo $item

# rather than using high or low like in arrays, you can use len instead
for idx in 0 ..< list.len:
  echo $idx & " - " & list[idx]

The last part of this collection thingy is Sets

Sets

A Set is a collection of distinct values. Sets has rules that makes it very different from Arrays and Sequences:

  • sets basetypes could only be an ordinal type (ie. a type that can be counted) with a certain size
    • int8-16
    • uint8/byte-uint16
    • char
    • enum
  • strings cannot be used as a basetype because there’s no clear order for a string’s values
  • having the same entry twice would result to dropping the other entries and only leaving one of each entry
var collection: set[int16]
assert collection == {}

# you can also declare a set with initial values
var collection2 = {'A', 'B', 'C'}

# since we only allow ordinal types, you can use the '..' to tell nim to list the values between the lower and upper bound
var collection3 = {'A' .. 'Z'}

# having the same entry twice would result to only retaining the first instance of that entry
var collection4 = {'A', 'B', 'A', 'C'}
echo collection4.repr # prints {'A', 'B', 'C'}

You can use sets on what you would normally use bitwise & for:

let comparee = {'a', 'B', 'c'}
let isAllLowerCase = {'A' .. 'Z'} * collection == {}

echo(isAllLowerCase) # false, since * operator is used as an intersection between the left and the right, wherein it would find 'B' as a valid value

We’ll get to know more about these guys once we get hands-on with a nim project :D

But first, we’ll have to go on with the basics. Next up, control flows. The ifs, the fors, the whiles, and the cases

© Daniel Cefram 2018