Nim Day 4: Function Calls
===================================================================

Or: A Brief Discourse on The Variety of Ways a Function May be
Called in Nim, With a Surprising Mention of Sloths

Nim has a rather unique combination of syntax and features for
function calls that add up to a very simple, flexible system that
provides a lot of convenience.  As a desired side effect, it also
Nim's functions a syntactical parity with "traditional" Object
Oriented styles as well as Functional styles of programming.  [1]


Proc vs Func
-------------------------------------------------------------------

By the way, I named this post "function calls", but Nim uses a
`proc` keyword, not `func`:

       proc hello() =
               echo "Hello phlog readers!"

So what gives?  What is the difference between a procedure and a
function anyway?

The key difference is that a function is supposed to return a
value.  Additionally, some purists will tell you that a function
should not have any side effects (should not change _any_ program
state outside the body of the function)!

Procedures are just blocks of code which can be called - they do
not have to return values and traditionally it was assumed that
something called a "procedure" might have side effects.

Of course, we know that many common procedural languages (such as
C, JavaScript) have "functions" which do not have to return values
and may have side-effects.  Interestingly, C and its many
descendants are considered "ALGOL-like" in syntax, yet ALGOL used
the `procedure` keyword (and the unloved ALGOL 68 shortened it to
`proc`, like Nim).

Arguably "procedure" is a more correct general term for these
callable chunks of code, since they may or may not fit a strict
definition of "function".  I don't think the semantics are worth
getting too worked up about, but I think it's also good to
understand and appreciate the difference in terminology.

(It's also worth noting that depending on the circles you travel
in, writing code with procedures that make all sorts of
unstructured changes to program state in 2018 is akin to writing
GOTO-laden "spaghetti code" in the 1970s and 80s (as Dijkstra's
famous "GOTO Considered Harmful" letter became gospel.))

Anyway, I'm going to use the term "function" and "procedure"
interchangeably from here on out.


Optional parenthesis for function calls
-------------------------------------------------------------------

You may have noticed the optional parenthesis when calling
functions such as `echo` in previous examples (in fact, I have
consistently left them out):

       echo "Hello World!"
       echo("Hello World!") # equivalent

There is nothing special about the echo() function which allows
this.

Any function which takes at least one parameter may be called
without parenthesis.  Let's make a little example:

       # callsugar1.nim
       proc foo(num: int) =
               echo num
       foo(5)
       foo 5

And compile and run it:

       nim c -r callsugar1
       ...
       5
       5

So `foo 5` is just syntactic sugar for `foo(5)`.  Any time I can
press the Spacebar key once instead of Shift+9 followed by Shift+0
"( ...  )" is a Good Thing!

Oh yes, sweet sugary syntax!  I crave your nectar like a fruit fly
craves the pungent flower that eventually traps and kills it.


UFCS
-------------------------------------------------------------------

Nim supports a really interesting feature called Uniform Function
Call Syntax.  Short explanation: it lets you call the function as
if it were a method of the first parameter.

Huh?

Let's use that `foo()` function above as an example:

       foo(5)
       5.foo() # same!

This might look a little more familiar with a variable:

       var mynum = 5
       mynum.foo()

"Holy crap!  That looks just like my Grandpa's old Java method
calls we keep under a greasy tarp out in the barn!"

That's the idea.

Between UFCS and the optional parenthesis sugar, we can have quite
a few variations.  Let's see if we can try them all:

       # callsugar2.nim

       proc noargs() =
         echo "I don't take any arguments."

       noargs()
       # noargs    <- this would be an error!

       proc onearg(a: int) =
         echo "I take this arg: " & $a

       onearg(5)
       onearg 5
       5.onearg
       5.onearg()

       proc twoargs(a: int, b: int) =
         echo "I take these args: " & $a & ", " & $b

       twoargs(5, 6)
       twoargs 5, 6
       5.twoargs(6)
       5.twoargs 6

And here's the results to prove it all works:

       I don't take any arguments.
       I take this arg: 5
       I take this arg: 5
       I take this arg: 5
       I take this arg: 5
       I take these args: 5, 6
       I take these args: 5, 6
       I take these args: 5, 6
       I take these args: 5, 6

Now, you'll have noticed that `noargs()` is the exception to all
of this excitement.  Why can't we call it without parenthesis?
The happy answer is that functions "first class" in Nim.

(First-class functions are treated like any other value in the
language - you can store references to them in variables, pass
them to other functions, or put them in data structures.  In other
words, functions are "first-class citizens".)

So we can't call `noargs` without parenthesis because Nim treats a
bare function name as a reference to the function, not a function
call.  (The compiler gives us an error telling us that we have to
_do_ something with the reference (such as discard it).)



Stropping
-------------------------------------------------------------------

Nim takes extensibility very seriously.  I probably _won't_ get
into templates or macros, but Nim has complete support for
metaprogramming.

But here's a fun thing to play with that takes two seconds to
learn: put backticks (`) around operators and reserved keywords to
redefine them!

       proc `!`(n: int) =
         for i in 1 .. n:
               echo "BANG!"

       ! 5

Results in:

       BANG!
       BANG!
       BANG!
       BANG!
       BANG!

More practically, you can give your custom type array-style access
by defining a method for the `[]` operator:

       proc `[]`(obj: MyWeirdObject, index: int) = ...

Neat!  Maybe we'll try one of those later when we look at defining
our own types.


Function overloading
-------------------------------------------------------------------

If you've not encountered them before, "overloaded" functions have
multiple definitions, each taking different numbers or types of
parameters.  This is a type of polymorphism (Greek for "many
forms" and "there are demons in this code").

       # foverload.nim
       proc sherlock(i: int) = echo "This is an integer!"
       proc sherlock(s: string) = echo "This is a string!"
       sherlock(5)
       sherlock("five")

Let's see how smart Sherlock is:

       $ nim c -r foverload
       ...
       This is an integer!
       This is a string!

This is a silly example, but there are lots of good reasons to use
polymorphism such as using it in place of if/else logic.

Also, it lets us program in Nim with...


Object Oriented Style
-------------------------------------------------------------------

So between the UFCS sugar and function overloading, we can make it
appear that we have traditional OOP methods:

       cat.makeSound() # meow
       cow.makeSound() # moo

But in fact, these would be defined like this:

       proc makeSound(x: Cat) = echo "meow"
       proc makeSound(x: Cow) = echo "moo"

Pretty straight forward.

This would be the end of the story, but there is actually a
`method` keyword in Nim.  What gives?

Well, most of the time Nim can figure out which function to call
at compile time.  In our above pseudo-example, it's clear to us
and the compiler which `makeSound()` to call based on the type of
the incoming parameter.  This is called "static dispatch".

However, there are situations where the type of a parameter can't
be known until runtime (this is not the same as having a function
which can take _multiple_ types - that's generics!) and so we
can't know which of the overloaded functions to call.  That
requires dynamic binding of the function and is called "dynamic
dispatch".

       method foo(n: int) = echo "Dynamic!"

This is one of those things to just file away in the big steel
filing cabinet in the corner of your mind so you can pull it out
when the situation arrives.  File it under "Nim: Multi-methods".


Functional style
-------------------------------------------------------------------

Functional programming is all the rage these days.

(I certainly caught the bug when I learned Scheme through a
wonderful book called The Little Schemer about a decade ago.
Since a lot of my professional work requires JavaScript, I've
become enamored with a functional programming library called
Ramda.  I've barely scratched the surface of what Ramda can do -
but it's amazing how much you can accomplish in a line or two when
you embrace a "point-free" existence!)

Nim isn't billed as a "functional programming" language and it's
certainly not going to fit certain purist definitions of that term
because it lets you get away with any sort of imperative nonsense
you like and because it doesn't have a huge amount of FP "helpers"
built into the language.

But has the essentials you need to write your own "pure"
functional code.

We have first-class functions which can be passed as parameters:

       # procparam.nim
       proc foo(n: int) = echo "Foo: " & $n
       proc numberify(n: int, f: proc) = f(n)
       numberify(5, foo)

(Crossing my fingers, I'm totally guessing that `proc` as the type
will work...)

       $nim c -r procparam
       ...
       Foo: 5

(Man, I love it when I guess correctly!)

You can assign functions to variables:

       # procvar.nim
       proc foo(n: int) = echo "Foo: " & $n
       let kittensLoveSkeletons = foo
       proc numberify(n: int, f: proc) = f(n)
       numberify(5, kittensLoveSkeletons)

(The output is the same as procparam.nim: "Foo: 5".)

And you can perform point-free (no variables) "method chaining",
which can be very satisfying:

       # methodchain.nim
       proc x2(n: int): int = n * 2
       proc plus10(n: int): int = n + 10
       proc toString(n: int): string = $n
       proc show(s: string) = echo s
       3.x2.plus10.toString.show

Result should be 16:

       $nim c -r methodchain
       ...
       16

Yessss!!!

By the way, I clearly sneaked some new syntax I'd avoided until
now, but which you probably implicitly understood: declaring the
return value of a function.

       proc foo(var1: TypeA, var2: TypeB): TypeC =
               # body of function

foo() takes a TypeA and TypeB and returns a TypeC.  if you like
thinking about this sort of thing, you're going to _love_
generics!

Speaking of declaring, Nim requires that functions be declared
before you call them.  Then what about circular dependencies?  Ah,
well I said they have to be _declared_, but they don't have to be
_defined_.  You can do this:

       # who wrote this and why!?
       proc a()
       proc b() = a()
       proc a() = b()

But don't.


Generics
-------------------------------------------------------------------

We'll just _touch_ on generics here.  Nothing heavy.  That can
wait for the Type System Discussion we're going to have to have.
You know, the one where I give you a stern look and say, "it's
time we had a talk about the type system," and both of us are kind
of embarrassed, but we know we have to go through with it to clear
the air because we've been walking on eggshells for, like, four
Nim sessions and it feels like a vacuum chamber in here, man.  I
can't breathe!

Here's a really simple form of generic function: it can take
either an int or a float (love that syntax):

       # genericproc1.nim
       proc foo(num: int | float) =
         echo "foozling: " & $num
       foo(5)    # foozling: 5
       foo(6.3)  # foozling: 6.3

An even more generic form takes _any_ type, which we name "T" and
use as the type of the parameter `num`.

       # genericproc2.nim
       proc foo[T](num: T) =
         echo "foozling: " & $num
       foo(5)
       foo(6.3)
       foo(true)

       $nim c -r genericproc2.nim
       ...
       foozling: 5
       foozling: 6.3
       foozling: true

The compiler will still protect us from passing values of types
which don't defined the `$` function to convert to string.

Well, I really thought I was going to make a nice short entry when
I started writing this at the beginning of the week.  I never
imagined it would take days to complete.  On the other hand, I
only had a few scattered hours here and there to spare.  I've
actually made very good use of my time and spent the rest with the
wife and kids, so that's a small triumph of its own.

I think I'll tackle the type system next.  If it starts to get out
of hand, I'll split it into multiple entries...but I'd much rather
start focusing on things specific to the end goal: creating a
Gopher server and Gopher client.

[1] Some folks think Nim's mildly irreverent syntax is the product
of an evil pickle-eating cult of sloth-monsters hell-bent on
turning all the world's information into a brown, sludgy paste.
That is simply not true.  [2]

[2] For most values of "paste".