Constants in C/AL
December 1st, 2011
Let’s start this post with a little example:
In the MSXML library, the XMLDocument class has a method called CreateNode, which accepts an integer representing the desired node type as its first parameter. One of the possible symbolic values for node type defined in MSXML is NODE_ELEMENT, which has a numerical value of 1. A call to CreateNode might look like this:
MyNewElement := MyXMLDocument.CreateNode(1, MyNodeName, MyNamespace);
However, the use of magic numbers is considered a bad idea by most professional programmers. We should probably use something like this instead:
MyNewElement := MyXMLDocument.CreateNode(NODE_ELEMENT, MyNodeName, MyNamespace);
But how are we going to implement this NODE_ELEMENT constant?
As you will probably be aware, constants are conspicuously absent in C/AL (remarkable, I guess, for a language that is supposed to be Pascal-based, or at least Pascal-inspired…). Boolean and numerical constants, and non-localizable string constants are usually implemented by setting a global variable to the desired value, and hoping that future maintainers of the code will be kind enough to leave the value alone.
My suggestion is to use a function instead. By its very nature, the return value of function is constant, i.e. cannot be assigned a new value from outside of the function. That also means that it is not affected by a carelessly added call to, say, CLEARALL, which would cause a constant implemented as a global variable to loose its value. Lastly, functions have global scope within the containing object, without introducing unnecessary global variables – a personal allergy of mine…
December 1st, 2011 at 10:48 am
Makes perfect sense, Jan.
But shouldn’t we ask MS for a CONSTANT concept in C/SIDE? They’re investing a lot in C/SIDE lately.
December 1st, 2011 at 10:51 am
Hi jhoek,
I couldn’t agree more!!
Your solution is also much easier to maintain if the constant should change in a future API release.
/Langbak
December 1st, 2011 at 10:57 am
That (using functions to define constants) sounds like a brilliant idea
December 1st, 2011 at 11:16 am
You are totally right - this principle (using a function) is even followed by the NAV standard:
Codeunit 1, functions ApplicationVersion, ApplicationBuild, ApplicationLanguage.
December 1st, 2011 at 1:48 pm
@Natalie: That’s right, although the situation for that is slightly different, I think. In my example, the NODE_ELEMENT function could have been Local=Yes, limiting its scope to the containing object, whereas the functions in codeunit 1 are called by the platform, e.g. for displaying the values in the about box. Theoretically, this would make these functions Local=No (i.e. visible to calling objects), although I’m sure the platform could also call local functions…
December 15th, 2011 at 9:33 am
[…] Bron : Zen & the Art of C/SIDE Development Lees meer… […]
January 16th, 2012 at 11:18 pm
Actually in a situation like that I prefer to firstly create a codeunit to encapsulate all the xml document and node manipulation. Assuming this is the case I would then create a global variable of type option called XMLDomNodeType with the value:
NODE_ELEMENT,NODE_ATTRIBUTE,NODE_TEXT,NODE_CDATA_SECTION,NODE_ENTITY_REFERENCE,NODE_ENTITY,NODE_PROCESSING_INSTRUCTION,NODE_COMMENT,NODE_DOCUMENT,NODE_DOCUMENT_TYPE,NODE_DOCUMENT_FRAGMENT,NODE_NOTATION
Then you don’t have to have a separate function for every value of the enumeration, and since the enumeration starts with 1, this mirrors an option type very nicely. This will also still lead to very readable code, such as:
MyNewElement := MyXMLDocument.CreateNode(XMLDomNodeType::NODE_ELEMENT, MyNodeName, MyNamespace);
January 17th, 2012 at 12:14 am
Yep, I agree. However, that works best for smaller, adjacent constant values (which is the case for the MSXML node types).
For flags, which typically have numerical values of 0, 1, 2, 4, 8, 16 etc., options quickly lose their advantages, I think.
January 17th, 2012 at 10:42 pm
Yes I agree, in the instance of flags I wouldn’t recommend using options. Quite frankly I would probably try to avoid ever doing anything with an API that involved flags inside of Navision if I could help it.