Returning complex types in AL Language

In Microsoft Dynamics 365 Business Central 2021 w1 (released in May 2021), a profound change was introduced to ways how we can design our applications

Until this version, the only way to return complex data types (like records, codeunits, Lists etc.) was using the var parameter (see example below).


 trigger OnRun()
 var
   SalesHeader: Record "Sales Header";
 begin
   FindSalesOrder('SO210001', SalesHeader);
   SalesHeader.TestStatusOpen();
 end;

 local procedure FindSalesOrder(OrderNo: Code[20]; var SalesHeader: Record "Sales Header")
 begin
   Clear(SalesHeader);
   SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
   SalesHeader.SetRange("No.", OrderNo);
   SalesHeader.FindFirst();
 end;

Although it allows returning any data type, working with var parameters is not as friendly as working with return parameters. For example, var parameters do not allow method chaining.

It was not possible in C/AL or AL Language. Until now!


 trigger OnRun()
 var
   SalesHeader: Record "Sales Header";
 begin
   FindSalesOrder('SO210001').TestStatusOpen();
 end;

 local procedure FindSalesOrder(OrderNo: Code[20]) SalesHeader: Record "Sales Header"
 begin
   Clear(SalesHeader);
   SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
   SalesHeader.SetRange("No.", OrderNo);
   SalesHeader.FindFirst();
 end;

With returning of complex types, we can chain methods similarly to C# (or any other modern object-oriented language) with returning of complex types.


 // With var parameter
 FindSalesOrder('SO210001', SalesHeader);
 SalesHeader.TestStatusOpen();

 // With returning complex types
 FindSalesOrder('SO210001').TestStatusOpen();

What is/isn’t possible to return

It is possible to return almost any data type.

  • Any simple type
    • Boolean, Integer, Text, Char, …
    • RecordRef, FieldRef, Variant
  • Any AL object
    • Records (Record “Sales Header”)
    • Pages (Page “Customer Card”)
    • Codeunits (Codeunit “Sales-Post”)
  • Selected DotNet objects
    • HttpClient, HttpContent, …
  • Other complex types
    • Lists (List of [Text])
    • Dictionaries (Dictionary of [Integer, Text])

The only things that are not possible to return are collections of complex types (something like List of [Records “Sales Header”]). However, it is not a limitation of return statements, but it is impossible to use collections of complex type in AL Language in general.

For this purpose, use Temporary Records instead.

Let’s chain it!

So how we can advance from method chaining in AL Language?

For example, imagine you want to work with data from the customer card for a customer from the sales header. Without chaining, the only way was to create a Customer variable and find the corresponding customer manually or using var parameter using the method in the Sales Header.

With chaining, we can use the getter method in the Sales Header that returns the customer (unfortunately, there isn’t the method yet). See the example below.

Example

Unfortunately, there aren’t any useful function in the base app yet, so the example uses methods as if they were in the base app.

I added a method procedure GetCustomer(): Record Customer to the Sales Header table and procedure GetShipToAddress(ShipToAddressCode: Code[10]): Record “Ship-to Address” to the Customer table.


 // Method in Sales Header table
 procedure GetCustomer(): Record Customer
 var
   Customer: Record Customer;
 begin
   Customer.Get(Rec."Sell-to Customer No.");
   exit(Customer);
 end;

 // Method in Customer table
 procedure GetShipToAddress(ShipToAddressCode: Code[10]): Record "Ship-to Address"
 var
   ShipToAddress: Record "Ship-to Address";
 begin
   ShipToAddress.Get(Rec."No.", ShipToAddressCode);
   exit(ShipToAddress);
 end;

Now we can get values (in our example, the value of email field) from Ship-to Address only with one line of custom code.


 procedure DoSomething(SalesHeader: Record "Sales Header")
 var
   EmailFromShipToAddressTable: Text[80];
 begin
   EmailFromShipToAddressTable := SalesHeader.GetCustomer().GetShipToAddress('ADDR-001')."E-Mail";
   Message(EmailFromShipToAddressTable);
 end;

Leave a Reply

Your email address will not be published. Required fields are marked *