.Net types in AL are reference types

11 Oct

This week I presented a session about .Net in the AL language at Directions EMEA 2019 in Vienna. And of course, I paid attention to the types in AL that represent .Net types, like TextBuilder, List, Dictionary, Http and JSON types. During the preparation of that session, I found a comment in the Microsoft documentation, below the documenation about HTTP, JSON etc., that I thought it could use some explanation:

For performance reasons all HTTP, JSON, TextBuilder, and XML types are reference types, not value types. Reference types holds a pointer to the data elsewhere in memory, whereas value types store its own data.

In this quote from the Microsoft documentation, the List and Dictionary type are not mentioned, but the same applies to these types.

The question is of course: what does it mean that they are reference types? How does it impact your code? For .Net developers, it’s quite obvious, they are used to working with reference types, but C/AL developers certainly are not so used to the concept. So if you move to AL code and use these new variable types, then you might run into unexpected behaviour. I though it would make sense to shine some light on it.

A reference type means that the variable doesn’t hold a value, but a reference to an instance of an object in memory. When you pass such a variable as a parameter to a function, then you are passing a reference to the object in memory. The receiving function works directly on that object in memory through the reference it received. Let me explain it with an example:

codeunit 50100 ListDemo
{
    procedure Demo()
    var
        Cust: Record CUstomer;
        NameList: List of [Text];
        Name: Text;
    begin
        GetNameList(Cust, NameList);

        foreach Name in NameList do
            Message(Name);
    end;

    procedure GetNameList(Cust: Record Customer; NameList: List of [Text])
    begin
        if Cust.FindSet() then
            repeat
                NameList.Add(Cust.Name);
            until Cust.Next() = 0;
    end;
}

The NameList variable is not passed by var to the function GetNameList. However, after the function call on line 9, the variable NameList will contain values. This is possible because the NameList parameter just holds a reference and the code on line 19 is working on the very same object in memory.

Let’s add one line of code that will destroy all of this. We add a Clear() command to the beginning of the function GetNameList.

codeunit 50100 ListDemo
{
    procedure Demo()
    var
        Cust: Record CUstomer;
        NameList: List of [Text];
        Name: Text;
    begin
        GetNameList(Cust, NameList);

        foreach Name in NameList do
            Message(Name);
    end;

    procedure GetNameList(Cust: Record Customer; NameList: List of [Text])
    begin
        Clear(NameList);
        if Cust.FindSet() then
            repeat
                NameList.Add(Cust.Name);
            until Cust.Next() = 0;
    end;
}

After the call, the variable NameList in the first function does not contain any value at all. This is the kind of situation that can really drive you nuts. If you debug this, you will see values being added to the parameter on line 20, but when you get back into the calling function the NameList is suddenly empty. While the previous example perfectly worked, this one doesn’t.

The reason is that the Clear() command removes the reference from the parameter. It doesn’t point to the original object instance anymore. And because AL types are automatically instantiated (we don’t have to call a constructor) a new instance will be created for us and the parameter will now hold a reference to that new object. However, the parameter was not passed in by var, so the calling function will not receive the new reference from the parameter. It will still hold the reference to the original object, but nothing happened on that original object. The function GetNameList worked on the newly instantiated object.

Of course, the solution is simple: add var to the parameter, and it works again.

codeunit 5010 ListDemo
{
    procedure Demo()
    var
        Cust: Record CUstomer;
        NameList: List of [Text];
        Name: Text;
    begin
        GetNameList(Cust, NameList);

        foreach Name in NameList do
            Message(Name);
    end;

    procedure GetNameList(Cust: Record Customer; var NameList: List of [Text])
    begin
        Clear(NameList);
        if Cust.FindSet() then
            repeat
                NameList.Add(Cust.Name);
            until Cust.Next() = 0;
    end;
}

Hope this makes a little bit sense to you!

2 thoughts on “.Net types in AL are reference types

  1. Hello Sir,

    I am Currently working on Reports with Barcodes in Business Central . While running report in Business Central Web Client the Barcodes are not showing in that Report, but if I run the same Report in Windows client the barcodes are showing properly.

    Note : 1. I am Developing an Application in Business Central On-premises.
    2. I installed all required Barcode fonts in my local system.

    Could you please give me suggestion, how can I resolve this issue.

    Thank you.,

    • I’m not an expert in barcode fonts. But I would for sure go for a different solution. Instead of installing barcode fonts on individual clients and hope that the browser will really use them, I would go with creating barcodes as an image and print those images on the report. There are plenty of web services out there to generate pictures of barcodes.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.