From Go to Nim

I have been using Go to build small project for a while, and I'm now looking into Nim.

Coming from Go to Nim gives certain challenges.

  • Go compiles directly to a binary. Nim compiles to c/c++ and depend on a c-compiler to compile to binary.
  • Go used { } to define blocks of code. Nim uses indention to define blocks og code, like Python.
  • In Go there are one primary terminal command go to manage packages, compile and run your project. Nim has nim for compilation and nimble for package management.
  • go.mod is in Nim called projectname.nimble.
  • go get both download a library and add this library to the local go.mod file. Using nimble install, Nimble downloades a library, but you must manually add the library to the local .nimble file to be able to use it in the project.
  • Go usually has few ways to do something and Nim seems to have many ways to do the same thing, making the code less readable:
    • parentheses can be omitted
    • method can be called with obj.method(x) or method(obj,x)

Go does not warn about modifying content in methods. If the method has a pointer receiver it works, if not, its just changes in the local copy and discarded when the method ends.

Lets Nimble

Nim's package manager is called Nimble.

Start a new project:

nimble init helloworld

Install a package:

nimble install illwill
nimble install illwill head
nimble install https://github.com/johnnovak/illwill

Alert: Remember to manually add the package, fx illwill to the projects projectname.nimble file in the root, fx:

# Dependencies
requires nim >= 1.6.10
requires illwill

To build or run:

nimble build
nimble run

Ofcouse nimble can do a lot more that this.

nimble refresh
nimble search illwill

Leetspeak Nim

Yes, Leetspeak was a thing...

This code shows som string mangling and access to argv command line items.

import std/strutils
import std/os

proc leetspeak(s: string): string =
  let r = s.toUpper()
  const leetfabet = [("E","3"), ("B","8"), ("C","["), ("L","1"), ("O","0"), ("A","4")]
  return r.multiReplace( leetfabet )

proc main() =
  for i in countup(1,paramCount()):
    if i>1:
      stdout.write " "
    stdout.write leetspeak(paramStr(i))
  stdout.write "\n"
  stdout.flushFile()

when isMainModule:
  main()

Compile and run with:

nim c -r leet.nim Hello World

Trying out Nim

Even though it has little adoptation, Nim looks like a cool promissing language! Lets try it out.

Getting started is easy, using choosenim

curl https://nim-lang.org/choosenim/init.sh -sSf | sh

After answering a few questions, you have Nim installed and can call:

nim -v

Hello World

Nim's package manager is called Nimble. Lets use it:

nimble init helloworld

Select "Binary" as "package type".

Nimble will now create a new folder called helloworld. The folder contains a file called helloworld.nimble which describes the new projects dependencies.

A simple hello world program is places in src/hello.nim it looks like this:

# This is just an example to get you started. A typical binary package
# uses this file as the main entry point of the application.
when isMainModule:
   echo("Hello, World!")

Like Python, Nim use whitespace (spaces, not tabs) indentation to indicate scoope. No {} is used.

To compile the program, write:

nim c src/hello.nim

or, to compile and run:

nim c -r src/hello.nim

or for projects, you ban use Nimble to build the project:

nimble build

To view the c source of your Nim program, try:

mkdir cache
nim c --nimcache=cache src/hello.nim

Now you can find the c source in the cache folder.

A bit more hello world.

import std/strutils

proc main() =
  let s = "Hello, World!"
  for c in s: # iterate chars in string
    if c=='o': # replace o with 0
      stdout.write "0"
    else:
      stdout.write c
  stdout.write "\n"
  stdout.flushFile()

when isMainModule:
  main()

It can’t Go on

I have been using Go as my primary language the last 4 years. I have developed several internal tools using Go and for most parts I really like it.

The good.

Its fast on all sides. Fast development time (OK, not Python fast). Fast compile time. Fast executeables.

It's strongly typed. I like to be able to see what a function accepts and returns. It's simple.

It has a really good standard library. Most of the time i have been able to get by using only the standard library. When the standard library is not enough, it has a nice package manager.

It can be updates without breaking code or deployment. I really like the Python language, but the way that Python updates can break virtual environment really nags me. Nice when your code just keeps running.

The bad.

Go tends to be a bit too verbose or detailed. I would prefer a little highter level of abstraction. I have a small library of helper functions to accomplish the most used functions without using Go's low level standard library.

The ugly.

Go is lacking in some language constructs that I would like. Mainly macros, but also optional function parameters.
I understand the value of dumb down the language for large teams, but for personal projects I would like to make such decisions, not have them forced by my programming language.