TL;DR or What is this post about?

In short: it's about me exploring - or at least getting into contact with -
a couple of interesting things:

X Window System APIs via Xlib bindings

low-level Linux APIs for elevating privilages, checking passwords

GCC options and some C

and of course the Nim language

Introduction

At my work we strongly discourage leaving logged-in accounts and/or unlocked
screens of computers. I happen to agree that locking your computer is a good
habit to have, so I've had no problems with this rule... Up to the point when I
switched from KDE to StumpWM (I wrote about it some time ago,
in this,
this
and this posts) and my
trusty Ctrl + Alt + L stopped working.

The only idea that came to my mind was to use the
venerable xscreensaver, but:
a) I didn't really need any of the 200+ animations (I just
wanted a blank screen) and b) I didn't like how the unlock
dialog looked like[1].

XScreenSaver and its dialog straight from the 80ties.

I needed something more lightweight (xscreensaver is ~30k loc of C[2]), simpler and either better looking or without any
UI altogether.

slock to the rescue

There's a site called suckless.org where
you can find some impressively clean and simple tools, implemented mostly in
C. You can read more about their philosophy
here, which I recommend as an
eye opening experience. Anyway, among the tools being developed there, there
is also slock - a very simple
and basic screen locker for X. It's 310 lines of code long and it's all
pretty straightforward C.

The program suited my needs very well: minimal, fast, and good looking.
Well, the last part it got through cheating, as slock simply has no
interface at all - but this means there's no ugly unlock dialog, so it's all
good.

Why Nim?

As I used slock I read through its code a couple of times. It seemed simple
and learnable, despite the fact that I knew nothing about X and didn't use C
seriously in 15 years. Fast forward to last week and I finally found some
free time and decided to learn some Xlib stuff. Re-implementing slock in
Nim looked like a good way of learning it: this may sound a bit extreme, but
it allowed me to gain exp points in two stats
simultaneously[3] - in Xlib
usage and Nim knowledge!

Nim is a very interesting language. I'd call it "unorthodox" - not yet
radical, like Lisp or Smalltalk, but also not exactly aligned with Java and
the like. For one tiny example: return statement in functions is optional
and if omitted, a function returns its last expression's value. That's
rather normal way to go about it; hovewer, in Nim you can also use a special
variable name result and assign to it to have the assigned thing returned.
It looks like this:

It's practically an idiom, a very common construct. Nim takes this idiom,
adds some sugar, adapts it to the world of static typing and includes in the
language itself. We can translate the above Python to Nim with very minor
changes[4]:

As I said, it's not a groundbreaking feature, but it is nice and
good to have, and it shows that Nim doesn't hesitate much when
choosing language features to include. In effect Nim includes many such
conveniences, which may be seen both as a strength and as a weakness. While
it makes common tasks very easy, it also makes Nim a larger language than
some others. It's not bad in itself, rather, depending on how well the
features fit together it's harder or easier to remember and use them all.
Nim manages well in this area, and also it most definitely is not
like C++ with its backwards compatibility problem, so I think even
Pythonistas with taste for minimalism will be able to work with Nim.

Being Nimble - the project setup

Many modern languages include some kind of task runner and package manager
either as part of stadard distribution or as downloadable packages. Nim
has Nimble, which takes
care of installing, creating and publishing Nim packages. Assumming that you
have Nim already installed[5], you can
install Nimble with:

Note the addition to the PATH variable: ~/.nimble/bin/ is where Nimble
installed itself and where it will place other binaries it installs. Make
sure to have this directory in your PATH before working with nimble.

The generated slock.nimble is a configuration file
for Nimble; it's written in a
NimScript, which looks like
a very recent development in Nim and it replaces the
previous INI-style config files. This means that many examples and tutorials
on the Internet won't work with this format. The most important
difference is the format of dependencies list for your app: it now has to be
a seq. For example, to add x11
library to the project:

The dependencies should be downloaded by Nimble automatically, but you can
also dowload them manually, like in the example below. You'll notice that I
also install a c2nim package
- I will say more about it later.

Workflow and tooling

Nim is a compiled language, but working with it proved to be comparable to
working with a dynamic language, mainly thanks to type inference and
blazingly fast compiler. You dcan ommit type declarations where they are
obvious from the context and Nim will deduce the correct type for you. It's
not a full program type inference like in OCaml, but rather a local type
inference as used in Scala or modern C++ or Java. Even with this limitation
it's immensely useful and reduces code verbosity by a lot.

Compiler speed is important, because it encourages frequent testing. If
compilation is going to take a long time you tend to "batch" changes in your
code together and only compile and run once in a while instead of after
every single change. This, in turn, makes it harder to find and fix
regressions if they appear. Dynamic languages work around this issue by
rejecting compilation step completely, at the cost of run-time safety and
performance. Nim - which is similar to Go in this respect - makes
compilation effortless and nearly invisible. The command for compile-and-run
looks like this:

Don't let that sudo bother you - it's there because you need to be a
superuser to be able to verify user password. In the final version it's done
by setting suid on the binary, but sudo is convenient for development.

While Nim's compiler and Nimble are very good tools, they're not enough to
work comfortably on more complex codebases. Nim acknowledges this and
provides a couple of additional tools for working with code,
like nimsuggest.
However, nimsuggest is rather new and it SEGFAULTed on me a
couple of times[6]. I used it via - of course - Emacs
with nim-mode, and again,
I encountered a couple of irritating bugs, frequent "Mismatched parens"
errors when trying to jump a word or expression forward. However,
when nimsuggest works, it does a good job, particularly its "Go
to definition" feature works and is very helpful.

Nim's definitive source of documentation is The Index, which does a
surprisingly well as a reference. Ctrl + f works just as well as search
boxes other documentation sites provide. Nim docs are also nice in that they
link to the source: you get a link to the function implementation beside its
documentation. I like this trend and I'm happy that more documentation is
like this - a quick peek at the source can sometimes save hours of unneeded
work.

In this project, I had to work with Xlib and turns out its
documented in man pages, and the pages were already installed on my system.
I don't remember installing them, so maybe they come with X by default on
Fedora. Anyway, for Xlib tutorial I used Xlib Programming Manual and for
reference I simply used the man pages: just type, for example, man
XFreePixmap and you get XCreatePixmap (3) man
page. The same is true for Linux/POSIX functions - try, for example,
man getpwuid.

That's it, for now

In the next part I'm going to show some Nim code, translated - both manually
and automatically - from C. I'll focus on Nim's language features that C
doesn't have and I'll show how they can be used to write shorter, safer and
more readable code. In the later, last part I'm going to write about Nim's
interop with C and various ways of connecting the two, using
Xlib as an example.

And it seems that JWZ doesn't like people modifying the
looks of this dialog, so I didn't even try. ↵

I recommend installing from GitHub - it's always
good to have the sources for your compiler and stdlib around, and you won't
get it if you install just the binaries. And master branch is stable:
checkout devel branch for the in-development code. ↵