AL and X++ side by side — reading the target language from day one

A genuine side-by-side comparison of AL and X++ for Business Central developers: table extensions, event subscribers versus Chain of Command, codeunit procedures versus object-oriented classes, Rec/xRec versus table buffers, trigger patterns versus attributes, error handling, transactions, Commit semantics, and data-access filtering — shown in real code both ways so a BC developer can read D365 code on day one.

What you will be able to do

Introduction

This chapter exists so that a Business Central developer can open a D365 X++ source file and read it on day one. It is not a tutorial — it assumes you know AL well and have already read chapter 1's structural overview.

Table extensions: adding fields and logic

```al tableextension 50100 "Customer Ext" extends Customer { fields { field(50100; "Credit Score"; Integer) { Caption = 'Credit Score'; DataClassification = CustomerContent;

Event subscribers versus Chain of Command

```xpp [ExtensionOf(tableStr(SalesTable))] final class SalesTable_CreditCheck_Extension { public boolean validateField(FieldId _fieldId) { boolean ret = next validateField(_fieldId);

Codeunit versus class

```al codeunit 50102 "Inventory Allocation" { procedure AllocateStock(ItemNo: Code[20]; LocationCode: Code[10]; Qty: Decimal): Boolean var Item: Record Item; AvailableQty: Decimal; begin Item.Get(ItemNo); AvailableQty := Item.CalcAvailableQty(LocationCode); if AvailableQty >= Qty then begin CreateAllocation(ItemNo, LocationCode, Qty);

Rec/xRec versus the X++ table buffer

Rec — the current record state (after the change) xRec — the previous record state (before the change)

Error handling: Error() versus throw/try-catch

AL error handling operates on a boundary model: Error() unwinds to the last Commit or Codeunit.Run boundary if Codeunit.Run(...) catches any error raised inside the codeunit There is no try/catch in the traditional sense (AL introduced TryFunction attributes later)

Transactions: Commit versus ttsbegin/ttscommit

```al procedure PostInvoice(var SalesHeader: Record "Sales Header") begin // Implicit transaction starts ValidateHeader(SalesHeader); CreateLedgerEntries(SalesHeader); Commit(); // <-- Hard commit. Everything above is now persisted.

Data access: filtering and queries

```xpp public Amount getOpenSalesLineTotal(CustAccount _custAccount) { SalesLine salesLine; Amount totalAmount = 0;

A complete worked example: posting extension

To tie everything together, here is a complete example showing how a BC posting extension translates to D365.

Knowledge check

Summary

AL and X++ solve the same problem — extending a standard ERP without breaking it — through different language paradigms. The BC developer arrives with the right instincts (extend, don't modify; validate before posting; think in transactions) but must learn different syntax and, in places, genuinely different semantics.