Unfortunately I’m not able to attend NAVTech Days this year, but I am paying attention from a far and saw some very interesting posts on Twitter about a new type available in the forthcoming Business Central 16.x release. The AL interface type.
The concept of interfaces won’t be new to any one from the object orientated world of programming languages. I first used them with Java and it’s great to see Microsoft expanding the AL language to give us more features that open up a whole new world of software design.
The AL interface type give us the ability to use the techniques of abstraction and loose coupling in AL. To explain this lets look at an interface declaration:
interface IErrorHandler { procedure HandleError(ErrorCode : Code[10]; ErrorMessage : Text[1024]); }
As we can see, the interface IErrorHandler declares a procedure but does not have a procedure body. The procedure is not implemented in the interface.
A codeunit must be created to implement the interface and provide the behaviour. Implementing codeunits must implement every procedure declared by any interface it implements. An important point to remember when designing interfaces.
To implement an interface, we use the implements keyword followed by the interface name after the codeunit declaration:
codeunit 50104 "Throw Error" implements IErrorHandler { procedure HandleError(ErrorCode: Code[10]; ErrorMessage: Text[1024]) var Errortext: Label 'Error Code: %1\Error Message: %2'; begin Error(ErrorText, ErrorCode, ErrorMessage); end; }
An interface can be implemented by many different codeunits, all providing their own behaviour. Lets create another implementation of IErrorHandler:
codeunit 50105 "Log Errors in Database" implements IErrorHandler { procedure HandleError(ErrorCode: Code[10]; ErrorMessage: Text[1024]) var ErrorLog : Record "Error Log"; begin ErrorLog.Validate(Code, ErrorCode); ErrorLog.Validate(Description, ErrorMessage); ErrorLog.Validate("Logged On", CurrentDateTime); ErrorLog.Insert(); end; }
So now we have two codeunits which both implement IErrorHandler in their own way. The compiler knows that any codeunit that implements IErrorHandler must implement the HandleError function, which means we can write generic, loosely coupled code to handle the processing of errors and pass in the implementing codeunit as required:
codeunit 50103 "Error Creator" { procedure ProcessError(ErrorHandler : Interface IErrorHandler) begin ErrorHandler.HandleError('Error1', 'This is an error message!'); end; procedure CallErrorHandler(PersistErrors : Boolean) var ErrorLogCU : Codeunit "Log Errors in Database"; ThrowErrorCU : Codeunit "Throw Error"; begin If PersistErrors then ProcessError(ErrorLogCU) else ProcessError(ThrowErrorCU); end; }
The ProcessError() method above takes a parameter of type Interface IErrorHandler, this means we can pass in any codeunit that implements IErrorHandler as seen in the CallErrorHandler() method.
A codeunit can implement multiple interfaces using comma separation:
codeunit 50105 "Log Errors in Database" implements IErrorHandler, ISomeOther, ISomeOther2 { // implementation here... }
Note: The I prefix on the interface name is not mandatory but is a common convention used in C#.
The interface type was revealed during the NAVTechDays 2019 opening keynote, which is now available on YouTube here (1:17:30).