Last year I did some videos about organizing code in Microsoft Dynamics NAV which I put on my YouTube channel. I wanted to do more, but got occupied by writing a book about learning dynamics NAV patterns and organizing a global set of classes around this subject.
Let’s continue where we left off and discuss the possibilities and challenges of implementing the arguments table.
Let’s go into it.
At the end of this blog you will be familiar with the Arguments table pattern, why we need it in Dynamics NAV and what are possible negative side effects.
Problem Definition
Within our C/AL programming language and programming in general we have some challenges.
Using to many arguments in a function
When creating functions we sometimes need a lot of parameters to give the information we require. Sometimes these parameters are optional, only required in some scenarios. This makes calling them quite hard. The code becomes less easy to read, sometimes spread across multiple lines.
Hard to change signatures
When refactoring code it is hard to change signatures of functions when they are called in many places of the system. Think about the Functions that create reservations for example. When changing the signature of these function you might end up changing and endless chain of codeunits.
No Function Overloading in C/AL
Our beloved language does not support overloading. What is that? I had to look it up too the first time. Overloading means creating functions with the same name and meaning that take different parameters effectively allowing you to be more flexible in your code.
For example creating a new DateTime in DotNet can be done in 12 different ways with different parameters effectively giving the same result, a DateTime.
Duplicating Option Definitions
Lastly, when calling functions that take an option field as parameter we have to duplicate the option value in order to make the code easy to read. And option values are hard to maintain anyway.
Solution
These challenges can be solved by grouping commonly used arguments in a single table and use that table as the parameter of a function. This is effectively using a table as a class.
Let’s look at some examples of candidates in our product
The legacy code of Dynamics NAV is full of examples, but let’s discuss two that you are bound to hit if you start working with the product, even if you don’t deep dive.
FindSalesPrice
This function in codeunit 7000 is called to calculate a sales price for an Item. It uses 10 parameters.
FormatAddr
This function in codeunit 365 is called to format an address in the system
Changing the signature
Imaging adding a field to this function, or change a datatype. The amount of code affected is pretty big and if you need to parameter only for one specific case you end up changing a lot of code for no purpose.
Compiler
Fortunately the compiler finds all instances where the function call is incomplete, but that does not mean we should use that to change all of them.
Let’s also make sure we understand that the sheer fact that NAV legacy code has these functions it is ok to do so. It does not match the basic principles of clean code.
The Argument Table
So the solution is to create a single table that holds the contract for the function. This would be similar to creating a class in DotNet and using that class as parameter.
When we add new fields to the table, we effectively do not change the signature of the function hence this acts as overloading allowing optional parameters to change the behavior of the code.
Examples in Standard Dynamics NAV
What if I told you that this one of the oldest patterns in Microsoft Dynamics NAV, dating all the way back to good old Navision Software. Would you believe me? I guess not, but it is true.
All codeunits that are used to post Journals are effectively argument functions. We use the Journal Line as an argument table to call into the posting routine. Imagine the effect if posting routines had all these fields as parameters.
When we call one of these codeunits nested inside another transaction we never actually insert the journal line in the database. We merely use the record variable as a placeholder in memory for the data.
Side effects
Although in my personal opinion the arguments is one of the greatest patterns to write clean code, there are some side effects
First off we need to write code to populate the arguments table. This requires us to write extra code we don’t need if we just call a function with let’s say 10 parameters. It does make the code cleaner and makes it intention easier to understand.
Also, the fact that the compiler does not catch adding a field to the table as a signature change can be a downside. Who has not abused this feature as “where used”. We would really need where used in order to perform a risk analysis when adding arguments.
Last but not least, one of the basic principles of events will be broken. The new events in NAV2016 have a built in warning system if a parameter that I inherit no longer exists. This mechanism does not understand if I delete a field of an arguments table. The extensions have the same challenge.
Example
Let’s look at an example. In NAV2015 the development team decided to implement email as an arguments table. This is table 9500 Email Item.
This table has all fields we need to send emails, as well as functions to send the email. The validation logic of the fields can be used to perform checks on the values. How nice and clean is that.
The arguments table is used in Codeunit 260 Document Mailing. Here you can see the coding that is required to use an arguments table.
A new, nice and clean way of writing C/AL code.
Naming Recommendations
When using arguments tables, I recommend adding the keyword “arguments” to the name of the table. This makes it one of the only, if not the only plural table name in Dynamics NAV.
Licensing Considerations
In essence Argument tables can be outside of a customer’s license file since we never insert data in the SQL Server database. However, when you want to use functions as methods of the arguments table it needs to be licensed. Reason for this is simple. The licensing engine is not aware that you want to run code that is tied to a temporary table, you might for example call code in a Production Order when running Business Essentials licensing. To make this work, Microsoft first needs to add a table type “temporary” to the properties
Want to know more?
I will create a video on this too soon. The Arguments Table is also part of my new book.