Container is a primitive type in X++. They serve many purposes like storage of blob data (like images), transferring of large portions of data, building hierarchical in-memory data structures, serializing objects, returning multiple values from methods – to just name a few common use cases.

For the past few years I've had the impression that container's performance was poor. I guess it comes from the R3 days when I wrote the Pedal to the metal blog. This R3 blog deals with how to write X++ code that is fully managed – as everything else requires slow interop calls.

Code like this would raise my eyebrows:

for (i=1; i<=conlen(infologMessages); i++)
{
    info(conpeek(infologMessages, i));
}

Why call conlen() for each iteration – it is not changing? I decided to find the overhead of calling conlen(), I assumed it would be significant due to an interop call.

Surprise!

A small test revealed that my dev VM could do a staggering 150 million calls to conlen() per second. In comparison I could "only" do 24 million calls to a private method. With these speeds, clearly there were no expensive interop calls. What was going on?

.NET reflector revealed that an X++ container is a System.Object[]. conlen() is just returning the value of the System.Object[].Length property, and conpeek is simply indexing the array System.Object[].GetValue(index). No interop required.

X++ container is a System.Object[]

Some usages of containers will result in interop calls – for example when serializing and deserializing. But many common case scenarios will not. Kudos to the X++ compiler team for this improvement. I can take my eyebrows down again – and I'll not spend another breathe worrying about container performance.