Sotolf's thoughts and oddities

A Little Nim

I really do enjoy programming nim, so I just wanted to do some propaganda, this time I will go through advent of code 2022 day 6

So basically the task here is to find sequences of unique characters in a string, seems like a pretty simple task, so first we create a function to see if a given string has only unique characters:

1proc all_different(str: string): bool =
2  var chs: seq[char]
3  for ch in str:
4    if ch not_in chs:
5      chs.add ch
6    else:
7      return false
8  return true

There aren’t really that much interesting here, we go through the string one character of a time, we have a temporary sequence of the characters that we have seen so far, and if it’s seen we bail and say false.

not_in is a bit fun here, it’s basically template sugar for contains with a not so ch not_in chs basically desugars to not contains(chs, ch) so if we want to use the in/not_in construction for our own structures we just ahve to implement the contains function for the struct.

1proc unique(str: string, count: int): int =
2  result = count
3  while not str[result-count..<result].all_different():
4    inc result

In the next function we get to do some more tricks, first of them is the implicit result variable, when we create a function in nim that does return something, an implicit result variable gets declared that we can use (it will get optimized away if we don’t use it) and if we use this result variable it will be automatically get return at the end of the scope, kind of like an automatic defer statement, which is pretty cool.

Also see that the function that we declared that takes in a string, now looks like a method on the string, that’s basically just syntactic sugar, so str.all_different() desugars down to all_different(string) it’s a small thing, but it just makes it feel nicer to program.

We go through the string slice by slice by indexing the string and when we found a unique string, we return the index of the last character that we found.

1proc start_of_packet(str: string): int = str.unique 4
2proc start_of_message(str: string): int = str.unique 14

For the next couple of functions, they are so small that we just have one-line definitions they just call the unique method with different counts. The only other little cool thing here is that we have str.unique 4 which desugars down to unique(str, 4) we see that much of nim is just quite c-like, but with some sugar that makes code look nicer.

I really like the ml-style function calling, so it’s what I usually end up using for function calling style.

1proc part1(ins: string) =
2  let ans = ins.start_of_packet 
3  echo "Part 1: ", ans
4
5proc part2(ins: string) =
6  let ans = ins.start_of_message
7  echo "Part 2: ", ans

The two functions here basically just use what we buildt up earlier and prints the result out so that we can get our results, nothing really interesting in this one that we haven’t already looked at.

1let streams = toseq (read_lines "day06.txt")
2
3part1 streams[0]
4part2 streams[0]

For reading in a file into a sequence of strings we have read_lines, which is a really nice function, it’s very useful, since reading a file line by lines is something that occurs really often in programming small utils. It does return an iterator over lines, so we use toseq to just stuff the iterator into a sequence.

We then call our functions on the first (and only) line in the file, and it’s done.

The whole little program can be found here

I really enjoy writing in nim, it’s kind of the right mix of high and low level for me, and it has so much nice little sugar that just makes programming in it fun, I rearly find some task where I just can’t find a way that I like to solve something, and it makes it pretty easy to just punch out a program that does what I want.

There is one thing that I would have kind of wished to have, and that is namespacing, some a bit more clear way in the code to segment out for example all the functions that extend strings or some other object I’m working with. The same is the case with imports, they always import everything unqualified, which is kind of nice in that it makes the code not have the namespaces everywhere, but feels kind of weird in the beginning. In the end it’s really not a problem, since a function in nim is defined based on the name and the parameters, but it some times makes the code feel a bit weird.