What are the types of arrays with variable size and accommodating different types in Nim?

111 views Asked by At

Nim is my second language after Python. Python has a universal array type, the "list" type. It has a changeable size and can accommodate any type. I am currently sorting out and studying Nim learning materials. It looks like there are many different types of arrays for all cases - tuples, arrays, openarrays, sequences etc. It's a bit confusing to study. I still haven't figured out if there are arrays with variable size in Nim, and arrays that can include different types of data.

Is there an analogue of the "list" type from Python, which is resizable and accommodates different types of data?

2

There are 2 answers

1
blakmius On
  1. array in nim is equivalent static arrays in C. to allocate it dynamically you need to ask nim allocator for it. in nim you have alloc, alloc0 (but be careful, after you ask allocator for a memory you need to track it lifetime manually)
var arr: ptr UncheckedArray[int] = alloc0(10 * sizeof(int)
for i in 0..<arr:
  echo arr[i]
dealloc(arr)

then with these you can create dynamically allocated array. in nim there is already one called seq you can see its sources it uses the same UncheckedArray in its implementation https://github.com/nim-lang/Nim/blob/devel/lib/system/seqs_v2.nim

  1. tuple in nim is more like namedtuple in python than default python tuples. you can give each field a name but still can index it by numbers. https://nimbyexample.com/tuples.html

  2. nim is statically typed language and seq or arrays can contain only values of the same type. but you can always use variadic objects, OOP, and pointers with casting

with variadic objects will look like this. for example json libraries in nim uses this approach

type
  MyType = enum
    Int
    Str
  A = object
    case t: MyType
    of Int:
      datai: int
    of Str:
      datas: string

var arr: array[2, A]
arr[0] = A(t: Int, datai: 42)
arr[1] = A(t: Str, datas: "hello")
for obj in arr:
  case obj.t
  of Int:
    echo "int obj:", obj.datai
  of Str:
    echo "str obj:", obj.datas

same using OOP


type
  DynObj = ref object of RootObj
  Int = ref object of DynObj
    data: int
  Str = ref object of DynObj
    data: string
var arr: array[2, DynObj]
var i = new Int
i.data = 1
arr[0] = i
var s = new Str
s.data = "hello"
arr[1] = s
0
Archar Gelod On

There's no built-in collection type in Nim that can hold elements of different types. It's almost exclusively feature of dynamically typed languages. You can use variadic objects, but please evaluate each time - do you really need them or you can use homogenous arrays instead.

For variable sized arrays there's a sequence type (seq). It can grow and elements can be removed just like with Python's list.

Tuples are more like objects, than arrays in Nim - they can hold elements of different type, but can't change structure. Also note that, unlike Python, tuple fields can't be dynamically accessed (indexes should be known at compile time).

type named = tuple[a: int, b: string]

let foo: named = (42, "ada") 
let bar = (42, "ada") # unnamed tuple of type (int, string)

assert foo.a == bar[0]
assert foo[1] == bar[1]

let i = 0
echo foo[i] # Error: i can't be known at compile time

openarray - is a special type that's only allowed as an argument. It provides a single immutable interface for other collection types.

E.g. here argument bar is openarray[char], so it can take any of array[size, char], seq[char] or string:

proc foo(bar: openarray[char]) =
  echo typeof(bar) # openarray[char]
  echo bar.len()
  for elem in bar:
    echo elem

foo(['a', 'b', 'c'])       # array of size 3
foo(@['d', 'e', 'f', 'g']) # sequence
foo("xyz") # strings are very close to seq[char] in Nim