Interfaces in AL

Overview of Microsoft Dynamics 365 Business Central Understanding Implementation vs Usage

Interfaces in AL were introduced in Business Central 2020 release wave 1 and provide a formal way to define behavioural contracts without tying code to a specific implementation. They allow developers to describe what capabilities are required, while leaving how those capabilities are implemented open and replaceable.

This approach reduces dependency on concrete implementations, improves reusability, and enables polymorphic behaviour, where the same call can execute different logic depending on which implementation is used. Interfaces are a core building block for designing flexible, extensible, and maintainable Business Central solutions.


What Is an Interface in AL?

An interface in AL defines a set of procedure signatures that implementing objects must provide. The interface itself contains no executable code. Instead, codeunits or enums implement the interface and supply the actual logic.

The AL compiler enforces the contract strictly. Any object that claims to implement an interface must implement all procedures exactly as defined, otherwise compilation fails.

An interface:

•Defines required capabilities
•Contains only procedure declarations
•Cannot be executed directly
•Must be implemented by other objects

An interface does not:

•Contain business logic
•Access tables
•Define UI behavior

How Interfaces Are Used Conceptually

Interfaces allow you to write code that depends on what an object can do, not which object it is. Variables can be declared as an interface type, and any implementation that fulfils the interface contract can be passed at runtime.

This enables:

•Substitution of business logic
•Removal of conditional branching
•Cleaner extensibility models
•Easier testing and replacement of logic

Interface Declaration (Code Example)

The following example defines an interface that represents an address provider.

AL

interface "IAddressProvider"
{
    procedure GetAddress(): Text
}
    

This interface declares a single responsibility: returning an address.

Implementing the Interface Using Codeunits

Multiple codeunits can implement the same interface, each providing a different behavior.

Company Address Implementation

AL

codeunit 50200 CompanyAddressProvider implements IAddressProvider
{
    procedure GetAddress(): Text
    var
        ExampleAddressLbl: Label 'Company address \ Denmark 2800';
    begin
        exit(ExampleAddressLbl);
    end;
}
    

Private Address Implementation

AL

codeunit 50201 PrivateAddressProvider implements IAddressProvider
{
    procedure GetAddress(): Text
    var
        ExampleAddressLbl: Label 'My Home address \ Denmark 2800';
    begin
        exit(ExampleAddressLbl);
    end;
}
    

Each codeunit fulfills the same contract but returns a different result.

Using Enums to Resolve Interface Implementations

Enums can implement interfaces and act as implementation selectors. This allows runtime resolution of which implementation should be used.

Example: Enum with Interface

AL

enum 50200 SendTo implements IAddressProvider
{
    Extensible = true;

    value(0; Company)
    {
        Implementation = IAddressProvider = CompanyAddressProvider;
    }

    value(1; Private)
    {
        Implementation = IAddressProvider = PrivateAddressProvider;
    }
}
    

This pattern is commonly used to map business choices to technical behavior.

Calling the Interface from a Page

The page below demonstrates how an interface is resolved and executed at runtime.

Example: Calling Interface from Page

AL

page 50200 MyAddressPage
{
    PageType = Card;
    ApplicationArea = All;
    UsageCategory = Administration;

    layout
    {
        area(Content)
        {
            group(MyGroup)
            {
            }
        }
    }

    actions
    {
        area(Processing)
        {
            action(GetAddress)
            {
                ApplicationArea = All;

                trigger OnAction()
                var
                    AddressProvider: Interface IAddressProvider;
                begin
                    AddressproviderFactory(AddressProvider);
                    Message(AddressProvider.GetAddress());
                end;
            }

            action(SendToHome)
            {
                ApplicationArea = All;

                trigger OnAction()
                begin
                    sendTo := sendTo::Private;
                end;
            }

            action(SendToWork)
            {
                ApplicationArea = All;

                trigger OnAction()
                begin
                    sendTo := sendTo::Company;
                end;
            }
        }
    }

    local procedure AddressproviderFactory(var iAddressProvider: Interface IAddressProvider)
    begin
        iAddressProvider := sendTo;
    end;

    var
        sendTo: enum SendTo;
}
    

Here, the page does not know which address provider is used. It only relies on the interface.

Extending Interfaces

Starting from Business Central 2024 release wave 2, interfaces themselves can be extended. This allows additional behavior to be introduced without breaking existing implementations.

Interfaces should always be designed with extensibility in mind, especially when published or reused across extensions.

Design Guidelines for Interfaces

When designing interfaces:

•Use clear, meaningful names
•Keep responsibilities small and focused
•Avoid adding methods after publication
•Document expected behavior
•Avoid circular dependencies

AL analyzers enforce many of these rules to prevent breaking changes.

Lists and Dictionaries of Interfaces

(Business Central 2025 release wave 1 and later)

From runtime v26, interfaces can be stored in List and Dictionary data types, enabling advanced runtime behavior.

Dictionary of Interfaces Example

AL

codeunit 50120 MyDictionaryCodeunit
{
    procedure MyProcedure(): Dictionary of [Integer, Interface "Barcode Font Provider"]
    var
        localDict: Dictionary of [Integer, Interface "Barcode Font Provider"];
        IProvider: Interface "Barcode Font Provider";
    begin
        localDict.Add(2, IProvider);
        exit(localDict);
    end;
}
    

List of Interfaces Example

AL

interface IShape
{
    procedure GetArea(): Decimal;
}

codeunit 50101 Circle implements IShape
{
    procedure GetArea(): Decimal
    var
        Radius: Decimal;
    begin
        Radius := 5;
        exit(3.14 * Radius * Radius);
    end;
}

codeunit 50102 Square implements IShape
{
    procedure GetArea(): Decimal
    var
        SideLength: Decimal;
    begin
        SideLength := 4;
        exit(SideLength * SideLength);
    end;
}

codeunit 50103 ShapeListDemo
{
    trigger OnRun()
    var
        ShapeList: List of [Interface IShape];
        Shape: Interface IShape;
        CircleShape: Codeunit Circle;
        SquareShape: Codeunit Square;
    begin
        ShapeList.Add(CircleShape);
        ShapeList.Add(SquareShape);

        foreach Shape in ShapeList do
            Message('The area of the shape is: %1', Shape.GetArea());
    end;
}
    

This demonstrates true polymorphism in AL.

Summary

Interfaces in AL provide a powerful and controlled way to decouple logic from implementation. They enable replaceable behavior, cleaner architecture, and long-term extensibility without invasive changes.

A well-designed interface:

•Represents a single responsibility
•Enables substitution without modification
•Is stable once published
•Forms the backbone of advanced extensibility patterns

Understanding interfaces is essential before working with event-driven architectures and advanced extensibility in Business Central.

Hot Topics in Business Central

Next Steps in Business Central