Change your way – Functional Programming In Dynamics NAV

I’m always ranting about “do not use global variables” in Dynamics NAV, this article is an attempt to give some backgrounds on the ranting.

In Microsoft Dynamics NAV we program in a language called C/AL, this language is related to Pascal, a language created by Nicklaus Wirth in the late 60’ties. Pascal belongs in a language family with Modula-2, Oberon, Delphi and many others.

Fun fact, one of the first Pascal compilers was written in Pascal and translated by hand into machine code by Wirth and his students.

And a fun relation between Dynamics and the history of Pascal. The man behind some of the most success Pascal compilers, PolyPascal, Turbo Pascal and Delphi is Anders Hejlsberg and his brother is Thomas Hejlsberg, one of the architects behind Dynamics NAV.

In the late 80’ties when PC-Plus (later Navision Software, later Microsoft) designed the first version of AL, Pascal was the most popular programming language in Denmark and a natural language choice for a new development system.

The first version of AL (character based version 3.00) worked with objects just as we know it today, but it was very limited compared to what we have today. The name later changed to C/AL with the release of the first Windows version, called Financials.

One of the main limits in AL was the lack of local variables. This of cause  lead to a heavy use of global variables (just called variables since there where no local><global definition). This continued into Financials even though Financials did have locals. The reason was, that parts of Financials was actually coded in the old character based version and the converted to Financials with the auto-converter.

So the reason that we are still fighting with less than optimal designed codeunit 80 and 90, is that they where programmed in a environment without local variables, limited call stack levels and other limitations.

So why does local variables matter?

First we need to look to another branch of programming. A branch called functional programming. The origin is math and a language called Lisp. Lisp is older than Pascal, and actually one of the very first programming languages. Lisp is often ridiculed due to a massive usage of parentheses and the beauty is overlooked.

I had my first encounter with Lisp at Copenhagen University, where they decided that we should learn a language that no-one had ever used, that turned out to be Lisp, followed up with ML. I learned a lot 🙂

In (purest form of) Lisp you don’t have global variables, and the only local variables are parameters to functions. So everything needs to be functions with parameters and return values.

This can be much harder to program, but is much easier to test.

There are plenty of other languages that follows the tradition started by Lisp – My current favorite is F# but I do have fond memories of ML (If I could find a compiler that worked back in the 90’ties).

The style of programming in these languages is called Functional Programming.

So what are some of the features in Functional Programming?

First-class and higher-order functions

A function is a value, just like an Int or a String. You can pass a function as parameter to another function. This is not really possible in NAV, only by some clever .NET tricks for creating delegates.
A classic use case for this, could be a sorting function that takes a comparison function as a parameter.

Pure functions

Think of a function as a mathematical function, it takes parameters and returns a value, nothing more nothing less. No side effects. When we throw a database in mix, this get more complicated.

Recursion

Recursion is not a functional programming exclusive feature, recursion was actually invented before Lisp, in the language ALGOL, by another Dane, the late Peter Naur. But recursion does not work well in a global variable dominated system.  Recursion can place a bigger strain on memory usage unless system support tailcall optimization a method to reduce the amount of call stack memory needed for keeping each recursion level in memory.

No side-effects

A side-effect is when a piece of code modifies anything outside its scope. A global variable is outside the scope of a function. The database is also very outside.

In a pure functional environment, there are no side effects.

Classic code mistakes in Dynamics NAV

So if we start looking at NAV code, with the knowledge of functional programming, what “mistakes” could we try to avoid:

Global variables should be avoided. Global variables, if used, should be immutable, a fancy computer science word for “readonly after create”, once written, never overwritten.

Hang over filters” – This is actually globals-on-globals. When people reuse the same Record variable and the properties on the Record stays on the Record. So everytime you use the .RESET function on a record variable, you’re properly doing something wrong. If Microsoft removed .RESET method, your code would actually improve, cause you would be forced to think about scope, and in a lot of places place inner code in loops in separate functions.

Real recursion only works if the globals are reduced to immutable usage.

Big functions – The only reason that functions can get so big are globals (again!) So if you reduce the amounts of globals, your functions will shrink in size.

What about testing?

A function that only takes parameters, and returns a value is very easy to test. You can just call the function and verify the return value with a test codeunit. But if you need to setup global variables and environment, then it suddenly becomes difficult to test the function, and usually you start your testing at a higher level. And if the higher level also has the same issues, testing becomes hard.

Conclusion – TL’DR

These ideas has been a integrated part of how I program for many years. Not that I’m “holy” or even close to that. But I do believe in “borrowing” good ideas from all corners of the computer science world. And functional programming has, for me, a very positive influence on how programs get structured and how easy they are to test and maintain.

There are lots of other aspects in functional programming that I didn’t cover in this already too long blog post, so reach me on Twitter if you want to talk function programming in Dynamics NAV.

(*) Thanks to www.xkcd.org for the comics to live up this boring tale.