good have an end goal for

Found at: sdf.org:70/users/ratfactor/phlog/2018-08-24-Nim-day-2

Nim Day 2: Hello Gophers!

Hey, good news!  I have an end goal for this little series: Write
a (very) simple Gopher server and Gopher client!  Seems
appropriate for a phlog, and the Gopher protocol is famously

Today we install Nim, write the traditional "hello world" program,
and take a quick tour of the language.


First, head on over to Nim's website:


Navigate to the Install page.

(By the way, I'll focus on the UNIX install, but Nim is a first
class Windows citizen as well.  A binary and instructions are
available on the Install page.)

As I write this in 2018, Nim provides an installation utility for
UNIX-like environments called `choosenim`.  If you trust the Nim

Once that's done, you're left with instructions to add the Nim
nstall dir to your $PATH.  Here's what I did (replacing  with
my username):

	echo 'export PATH=/home//.nimble/bin:$PATH' >> ~/.bashrc
	source ~./.bashrc

Now you're ready to create a Hello World program.


However, you're too crafty to do something risky like running
unknown scripts, right?  So you're going to do it like this:

	$ cd /tmp
	$ curl https://nim-lang.org/choosenim/init.sh > getnim
	$ less getnim

Now you can review the script before running it.  You can confirm
for yourself that it does as it claims:

	# This script performs some platform detection, 
	# downloads the latest version of choosenim and 
	# initiates its installation.

(I think one of the most impressive things about this script is

Bad news for the paranoid, though.  Turns out that this script's
Nim, of course) from Github and run *that*.

You can read the source for `choosenim` here:


But ultimately, you either trust the binary or you don't.

So for the truly paranoid, you're going to need to go the source
tarball installation route (which is also on the Install page.

But are you *really* going to audit all of the source before you
compile Nim yourself?  At some point, you have to trust something.

(Hmmm...this is starting to get philosophical and we have a lot of
the best installation method for you.  Me?  I trust the Nim devs.
Beyond that, I have backups and my secrets are encrypted.)

Hello World

First, let's make sure you have the compiler successfully
nstalled and in your $PATH (or Windows equivalent)

	$ nim --version

s always a variant of Hello World.  So let's type one up and see
f we can compile and run it.  So fire up Microsoft Word and let's

Actually, if you like, you might want to install a Nim-specific

Create a new file:

	# hello.nim
	# As you can tell, these are comments
	echo "Hello my little gophers!"

Compile this treasure:

	$ nim compile hello.nim

Run it:

	$ ./hello 
	Hello my little gophers!

**Woo!  Time to celebrate with a big ol' can of beans!**

Since we have something to examine, let's take a peek at what was
created for us.  First, how big is the executable?

	$ du -h hello
	204K  hello

Ouch!  That's pretty big!  Ah, but that's a development build with
"runtime checks" and no optimizer.  We can probably do better with
a "release" build:

	$ nim --help
	  --opt:none|speed|size   optimize not at all or for speed|size
	                          Note: use -d:release for a release build!

	$ nim compile --d:release hello

Now how big?

	$ du -h hello
	88K  hello

Ah, much better.  Not that it matters, but can we reduce that even

	$ nim compile --d:release --opt:size hello
	$ du -h hello
	44K  hello

That'll do.  Of course, the equivalent C is smaller:

	$ cat > chello.c
	int main(void){
	  printf("Hello World\n");
	  return 0;

	$ gcc chello.c -o chello
	$ du -h chello
	12K  chello

But the Nim version has far more "stuff" in its executable.
There's a whole Nim standard library in there!  Check out the
nimcache/ directory which was created for us:

	$ du -h nimcache/*
	4.0K  nimcache/hello.c
	4.0K  nimcache/hello.json
	4.0K  nimcache/hello.o
	148K  nimcache/stdlib_system.c
	52K   nimcache/stdlib_system.o

Yeah, that's 148Kb of *stuff* in Nim's included stdlib_system.c.
Feel free to read it, but it's largely machine-generated.  Same
for the string "gophers" reveals this delightful line:

	$ grep gophers nimcache/hello.c
	STRING_LITERAL(TM_xLHv575t3PG1lB5wK05Xqg_3, "Hello my little gophers!", 24);

As your code gets bigger, the Nim standard library does not.  It's
a fixed, statically-compiled cost, and therefore easy to bear.

The wonderful thing is that even as you add more things from Nim
libraries, they're also statically compiled into your executable,

Since we have them, here's some other comparisons between hello
and chello (our 'C' hello).

Nim hello:

	$ file hello
	hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), 
	dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, not stripped

	$ ldd hello
	linux-vdso.so.1 (0x00007fffc29db000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f523e713000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f523e34a000)
	/lib64/ld-linux-x86-64.so.2 (0x0000558719ec9000)

C hello:

	$ file chello
	chello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), 
	dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, not stripped

	$ ldd chello
	linux-vdso.so.1 (0x00007ffe4a90e000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f37efbea000)
	/lib64/ld-linux-x86-64.so.2 (0x000055bac2c1e000)

So the only difference between the executables (besides size) is
that Nim dynamically links to `libdl` (for dynamic library
functions) from the standard C library.

*The point is, Nim writes C so you don't have to!*

A quick tour of Nim

We "ate our vegetables" by diving deep into that mundane Hello
World.  Now we can enjoy ourselves.

There is (for now) a really fun "Easter egg" built into the Nim

	$ nim secret
	Hint: used config file '/home/...' [Conf]
	Hint: system [Processing]
	Hint: stdin [Processing]
	>>> 1+1
	>>> var foo = "A string"
	>>> echo foo
	A string

Wait!?  Nim has a REPL*?  Yeah, Nim can run Nim code at compile
time as well as generate output source and this "secret" feature
lets you treat Nim as an interpreter.  (There are some things that
aren't available in the secret REPL, but nothing we need yet.)

*REPL stands for "Read-Eval-Print Loop" and gives programmers
mmediate feedback for each statement.  They're incredibly handy
for learning a new language and just trying things out.

So continuing on, we can now use Nim as a calculator:

	>>> (3+3) * 10          

Here's a string with escaped (backslashed) quotes:

	>>> "hello \"world\""
	hello "world"

Nim has "raw" string literals:

	>>> r"Raw strings where \ backslashes mean nothing!"
	Raw strings where \ backslashes mean nothing!

And "long" string literals:

	>>> """Long string literals which
	... can even include newlines and "quotes"!   
	... And slashes \\\ ///"""
	Long string literals which
	can even include newlines and "quotes"!
	And slashes \\\ ///

Variable symbols are declared with an explicit type:

	>>> var x: int
	>>> x = 5
	>>> x

Or they can be be inferred at compile time:

	>>> var x = 5
	>>> x

There are also constant symbols which must be assigned at compile
time and 'let' symbols who can be assigned at runtime, but whose
values must never change!

We have tuples which are structures with named fields:

	>>> var gopher = (name: "Ratfactor", location: "Underground")       
	>>> gopher.name
	>>> gopher.location

(That's a tuple literal, you can also declare a variable as having
a tuple type.)

We have arrays which cannot be resized:

	>>> var foo = ["a", "b", "c"]
	>>> foo[0]
	>>> foo[0]="x"
	>>> foo
	["x", "b", "c"]
	>>> foo[3]="z"
	stack trace: (most recent call last)
	stdin(53, 4) Error: index out of bounds
	Error: unhandled exception: index out of bounds [ERecoverableError]

And sequences, which can be resized:

	>>> var foo = @["a", "b", "c"]
	>>> foo[0]
	>>> foo.add("d")
	>>> foo
	@["a", "b", "c", "d"]

To see if a value is in an array or sequence, you can use `in`:

	>>> "a" in foo

For control flow, we have a very nice `case` statement which can
match multiple values, ranges, and strings.

	>>> let foo = 3
	>>> case foo:
	...   of 1,2: echo "Too low!"
	...   of 3: echo "Just right!"
	...   else: echo "Too high!"
	Just right!

Case also evaluates as an expression, so you can do things like

	>>> echo case foo:
	...   of 1 .. 3: "Okay"
	...   else: "Not okay"

`elif` statement for "else if":

	>>> if foo == 2:
	...   echo "argh!"
	... elif foo == 3:
	...   echo "barg!"
	... else: 
	...   echo "narg!"         

While statements are pretty standard:

	>>> var foo = 5
	>>> while foo > 0:
	...   echo "Hey gophers!"
	...   dec foo
	Hey gophers!
	Hey gophers!
	Hey gophers!
	Hey gophers!
	Hey gophers!

The for loop is quite nice for iterating using the 'in' keyword:

	var foo = ["Nim","Is","Cool"]     
	>>> for word in foo:
	...   echo word

	>>> for idx, word in foo:
	...   echo idx, word

Okay, let's end this little tour with procedures.  Here's a silly
one that adds 1 to a number:

	addOne(num: int): int =
	...   return num+1
	>>> addOne 7

One of my favorite things about Nim procs (and something I've
the `result` variable:

	>>> proc addOneSometimes(num: int): int =
	...   result = num + 1
	...   if num == 3:
	...     result = 17     
	>>> addOneSometimes 1
	>>> addOneSometimes 2
	>>> addOneSometimes 3

See how that works?  The variable `result` is implicitly declared
for you using the return type of your function.  I especially love
using `result` when the function requires me to work in stages,
creating temporary variable to store possible return values.  (I
can't think of an exaple off the top of my head just now, but it


Okay, that's quite enough of a taste for now.

lot of "modern" conveniences.  It has a "script" feel but compiles
to fast, native binaries.

Until then, happy hacking!