Friendship Ended with Go
For the last five years, I've been using shell scripts to do most of my scripting work. Shell scripting is great because of the wide range of utilities that you have access to and the relative ease with which you can get things done.
Shell scripts do, however, have their problems. For the last while, when I've needed to write something bigger, faster or more optimised, I've used Go. For the uninitiated, it's a systems-ish programming language that was developed at Google. It compiles to native binaries and is being used a ton to write server-side applications right now. Go's main talking points are that you can use it to write really simple and readable code, and that you can write a web server in a really small number of lines.
Unfortunately, the promise of simple and readable code is a bit of a lie. As far as I've experienced, Go's syntax and standard library has been simplified and streamlined to the point where trying to do anything complicated leads to unwieldy and excessively verbose code. It's also notable that Go lacks true generics, really wants you to use a specific folder structure, complains when you don't put all your projects under one directory, and other tiresome things.
So, I'm looking for something else.
Now Nim is my Best Friend
I originally found out about Nim from some random guy on /g/ who would shill it in every thread.
It seems pretty cool. Some of its features include:
- Nim code looks a lot like Python. In fact, you can just copy something from Python and there's probably an 80% chance that it will work fine.
- The Nim Compiler transpiles your code to C/C++/Obj-C/JS, so you can take advantage of all the cool features and optimisations of GCC when you're generating a binary
- Memory management isn't autistic
- The garbage collector is sane
- Writing unsafe code is easy if you need to do that
- You can overload literally everything if you want
- Nim has the best metaprogramming support I've ever seen
Now let me show you how Nim does some basic things.
Variables and Types
Now we compile it:
nim c file.nim
0 b These are all the same variable: (name: "Bob", age: 22) (name: "Bob", age: 22) (name: "Bob", age: 22)
What's notable here is Nim's case-insensitive view of variable names. While some people don't like this, I'm a firm believer that if you have two variables whose names differ only in case, you're not very good at naming things. Nim's approach here allows a programmer to write a library using camel case names, and for somebody to use that library in their code with snake case names.
It's also notable that procedures are first-class types in Nim, meaning you can pass them around like syphilis in France during the early 1500s.
In this example, note the simple generic syntax. Nim has by far the easiest generics of any language that I've used. Simply annotate your proc with [T], use T in your arguments, and then you can switch on types later if you really want.
One of the main differences between a template and a procedure is argument evaluation. A template's arguments are evaluated lazily, whereas a proc's arguments are evaluated when it is called.
The withFile template example shows some more advanced usage of templates. Templates are a very powerful feature, and allow you to easily implement light AST manipulation.
If you want to manipulate the AST a bit more and do super complicated stuff, macros are here.
If you want do a whole lot more than this, you'll need to read the docs.
Conditionals in Nim are a lot like those in Python.
It's important to note that switches in Nim must cover all possible values. You can do this with a..b ranges, using else, or by stating all possible cases when you're talking about an enum.
Loops and Iterators
As you can see, while loops are as you would expect and for loops are the same as in Python. The creation of custom iterators in Nim is much better than in Python. In Nim, they don't require the declaration and instantiation of a whole class and have much simpler syntax.
A Few Miscellaneous Examples
The examples below are either not discrete language features or I didn't feel the need to give them their own category.
writeFile("/tmp/test", "Testing") echo readFile("/tmp/test")
Working with files in Nim is as wonderfully easy as in Python. You can see two different ways to read/write to files above, where the first deals with opening/closing the file for you, and the second does not.
You can use pragmas to access a ton of advanced and special language features. In this example, importc allows you to access a C function from Nim. For single function, you can use the form shown to declare the printf function, and the next example shows how to create fast-and-loose bindings to C++ engine.
In conclusion, Nim's better than python and go for my purposes. I will now proceed shill Nim in /g/ threads for at least a little while.