The 3 E's

Lee Hawthorn November 19, 2023 #Nim #Python #Life

I suppose it had to happen despite my best intentions. I finally feel like a specialist. It's probably got something to do with my age and where I work, more on that later. Feeling like a specialist is good.

Life as a generalist is good, we learn to work with others early and develop connections. We can solve problems by knowing enough and knowing the right people at the right time.

As a specialist I feel more exposed at times and I still see the world is changing faster than I can keep up with it. I can sense the ground moving under my feet, and I'm enjoying the ride.

My focus now is on holding back and transferring skills to others, I still like to get my hands dirty. In fact - some people get surprised when I do mundane work which is odd. I highly recommend other specialists try it.

Learning something new still comes easy and like other enablers I still think Python is the best tool for solving most problems and R is still the best tool for stats.

My start with Python back in 1999 was not good, back then, I was leading a college team for an end of year project competition. My team was working with PHP and, we were the underdogs. The favourites were a team using Python. They ended up having tech issues, and couldn't present. I don't know how, but my team ended up winning. Life took a turn after this, but that is a story for another day.

I sometimes wonder if the other team had won, how my life could have been different. Ignoring Python for the 2.0 era. My path crossed back with Python in the 3.0 era. That's not so bad I suppose. I missed the early days when tooling was less developed.

With any technology it's good to see how it performs on the edge. Good to know far we can push it. It's preferable to find this out before you actually need that level - stress test if you will.

Although that's not perfect, as technology can get better and more resilient in the future. Time for an enabler is the most important variable. We don't always get the opportunity to stress test.

I wanted to stress test Python soon after learning it. Wondering how efficient it was, at hard problems.

At the time, the only way I found to push Python was querying archived Nasdaq data - I could see the processor cores bouncing around on linux, I later learnt this was due to the infamous GIL. Don't get me wrong, I still feel Python today with the extensive library is still the go to. Most problems don't require the level of Nasdaq data processing.

Having the right tools in the box is important for enablers.

Ever since running Nasdaq data my mind has been open to a tool that is expressive, efficient, elegant AND has close to the metal performance for things like web/mobile/data/glue/edge.

There are several languages on the horizon trying to solve different problems.

I'm kicking tyres of NIM - I'm possibly being driven by my Python experience described above :-)

It's at 2.0 at the time of writing, the tools haven't reached maturity and library can use more engineers, the community isn't massive, but from initial working it seems to have the 3 E's with close to the metal performance.

The WACC thing popped into my head the other day. WACC is the weighted average cost of capital. Finance peeps use it for a variety of things.

Let me take you through this code below to calculate the WACC, if you squint it looks a lot like Python.

import decimal

This code imports the decimal library, this code came from the community. It provides objects we can use store Decimal values and functions to operate on Decimals.

The type is labelled DecimalType and the procedure to create a Decimal value is called newDecimal()

The docs are the code for this library, due to the 3 E's I found it easy to see what the library does.

I found this library a bit weird as I had to enter newDecimal(100) for an int based decimal and for a float it was newDecimal('223.50') Also, when I was writing the WACC formula it wasn't efficient or elegant.

With NIM we can easily overcome these problems.

type Dec = DecimalType

This creates an alias named Dec equal to DecimalType. This gives me control over what I type. Dec being quicker type that DecimalType.

Nim has template features that let us substitute code at compile time. I want to avoid passing strings into newDecimal().

template `'dec`(s: string): Dec = newDecimal(s)

This template allows me to write:

let
  e = 1000000'dec
  d = 2000000'dec
  rE = 0.14'dec
  rD = 0.07'dec
  t = 0.3'dec

Let in NIM creates single assignable variables and there are consts and vars to cover all use cases.

Nim has two types of functions.

  1. Proc is function that has side effects.
  2. Func is a pure function with no side effects.

I've not had much time with NIM with everything else going on but I want to go deeper.

I wrote the Proc below, with help from community and chat gpt, to calculate WACC:

proc wacc(e, d, rE, rD, t: Dec ): Dec  =
  let
    v = e + d
    eV = e / v
    dV = d / v
    adjRD = rD * (1 - t)

  eV * rE + dV * adjRD

This proc takes in DecimalType and returns DecimalType

I call the proc with :

let w = wacc(e, d, rE, rD, t)
echo w

The complete code is listed below.

import decimal

type Dec = DecimalType

template `'dec`(s: string): Dec = newDecimal(s)

proc wacc(e, d, rE, rD, t: Dec ): Dec  =
  let
    v = e + d
    eV = e / v
    dV = d / v
    adjRD = rD * (1 - t)

  eV * rE + dV * adjRD

let
  e = 1000000'dec
  d = 2000000'dec
  rE = 0.14'dec
  rD = 0.07'dec
  t = 0.3'dec

let w = wacc(e, d, rE, rD, t)

echo w

This has the 3 E's in my opinion. It has Python indentation rather than { } but this is not a problem, coming from Python.

I won't go into it much here, NIM is currently compiled to C by default. It then uses highly optimised C compilers with years of R&D to spit out a binary. It runs on Windows, Mac and Linux and you can use it for embedded, web, systems.

Oh, and the garbage collector is deterministic, and can be turned off for embedded crowd.