With AL we have multiple options for how we write code, in this video I investigate two different methods of writing the same thing. Check it out:

In this video, Erik explores the concept of syntactic sugar in AL for Business Central — the idea that you can express the same logic in different ways that don’t change what the code does, but do change how it reads and feels. He walks through a practical example of how the implicit Rec variable works on table objects, and why you need to pick a consistent style.
What Is Syntactic Sugar?
Syntactic sugar is a programming concept where the language offers different ways to write the same thing — making code easier to read or write without changing the underlying fundamentals. AL has some interesting characteristics here: it looks like it’s object-oriented in some ways, but it doesn’t have true inheritance. There’s no base report that other reports inherit from in a classical OOP sense. But we do have syntax that looks that way, and that gives us choices in how we write our code.
Setting Up the Example
Erik starts by creating a simple table with a primary key and a description field — a classic minimal table setup:
table 50109 MySugarTable
{
Caption = 'MySugarTable';
DataClassification = ToBeClassified;
fields
{
field(1; P; Code[30])
{
Caption = 'P';
DataClassification = ToBeClassified;
}
field(2; Description; Text[200])
{
Caption = 'Description';
DataClassification = ToBeClassified;
}
}
keys
{
key(PK; P)
{
Clustered = true;
}
}
}
It’s a good principle that if you create a function related to a table record, you put that function on the table object so it’s available wherever that record is used. With that in mind, let’s look at the two styles.
Style 1: Passing the Record as a Parameter
The first approach is to explicitly pass the record into the function as a parameter:
procedure Test(var Sugar: Record MySugarTable)
begin
Sugar.Description := 'Hello';
end;
To call this, you’d write something like:
procedure testtest()
var
Sugar: Record MySugarTable;
begin
Sugar.Test(Sugar);
Message('%1', Sugar.Description); // Shows 'Hello'
end;
This function is completely self-contained and portable. You could move it to a different object entirely and it would still work without any changes because everything it needs is passed in as a parameter.
Style 2: Using the Implicit Rec
The second approach leverages the implicit Rec variable that exists on every table object. Instead of passing the record in, you just work with Rec directly:
procedure Test()
begin
Rec.Description := 'Hello2';
end;
Now the calling code becomes cleaner:
procedure testtest()
var
Sugar: Record MySugarTable;
begin
Sugar.Test();
Message('%1', Sugar.Description);
end;
When you call Sugar.Test(), the Rec inside the function refers to the Sugar variable. This is the syntactic sugar — it’s the same operation expressed differently.
Understanding the Scoping
An important nuance comes up with scoping. If you have both an implicit Rec (the table’s built-in record reference) and a local parameter also named Rec, which one wins? If you’ve seen Erik’s earlier video on scoping, you’d know that the closer variable takes precedence — the parameter is closer in scope than the implicit Rec, so the parameter is what gets addressed.
You can actually see this in the VS Code editor: the implicit Rec and a parameter named Rec are highlighted in different colors, giving you a visual cue about which one you’re referencing.
// These two functions are effectively the same:
procedure Test()
begin
Rec.Description := 'Hello2';
end;
procedure Test(var Rec: Record MySugarTable)
begin
Rec.Description := 'Hello2';
end;
Note that you can’t actually have both of these on the same table at the same time — the compiler will complain about an overload that looks the same, since the parameterless version implicitly receives Rec.
A Real-World Example: The Clone Pattern
Erik shares a practical scenario that prompted this whole discussion. While working on the next version of his BCCL tool, he needed to clone records. Here’s the pattern he landed on:
procedure Clone(): Record MySugarTable;
var
NewSugar: Record MySugarTable;
begin
NewSugar := Rec;
NewSugar.P := IncStr(Rec.P);
NewSugar.Insert();
exit(NewSugar);
end;
And the calling code looks clean and readable:
procedure testtest()
var
Sugar: Record MySugarTable;
NewS: Record MySugarTable;
begin
Sugar.Test();
Message('%1', Sugar.Description);
NewS := Sugar.Clone();
end;
The line NewS := Sugar.Clone(); reads beautifully — it’s immediately clear what’s happening. This is where the implicit Rec style really shines.
The Complete Source Code
Here’s the full source showing both the table and the codeunit together:
table 50109 MySugarTable
{
Caption = 'MySugarTable';
DataClassification = ToBeClassified;
fields
{
field(1; P; Code[30])
{
Caption = 'P';
DataClassification = ToBeClassified;
}
field(2; Description; Text[200])
{
Caption = 'Description';
DataClassification = ToBeClassified;
}
}
keys
{
key(PK; P)
{
Clustered = true;
}
}
procedure Test()
begin
Rec.Description := 'Hello2';
end;
procedure Test(var Rec: Record MySugarTable)
begin
Rec.Description := 'Hello2';
end;
procedure Clone(): Record MySugarTable;
var
NewSugar: Record MySugarTable;
begin
NewSugar := Rec;
NewSugar.P := IncStr(Rec.P);
NewSugar.Insert();
exit(NewSugar);
end;
}
codeunit 50100 "My Sugar Test"
{
procedure testtest()
var
Sugar: Record MySugarTable;
NewS: Record MySugarTable;
begin
Sugar.Test();
Message('%1', Sugar.Description);
NewS := Sugar.Clone();
end;
}
Advantages and Disadvantages
- Implicit
Recstyle — Cleaner calling syntax, operates on the specific record instance, reads more like object-oriented code. But the function is tied to the table object and always operates on that particular record. - Explicit parameter style — More portable, self-contained, and can be moved to other objects. But the calling syntax is slightly more verbose.
Sometimes operating on the specific record is an advantage; sometimes it’s a disadvantage — it depends on what you’re doing.
The Key Takeaway: Be Consistent
Erik’s main message is clear: pick a style and stick with it. When he found himself mixing both styles on the same object — using implicit Rec in one function and explicit parameters in the function right next to it — he stopped and made himself choose. Mixing styles on the same object is messy and confusing for anyone reading the code.
In his case, he went with the implicit Rec approach because it produced cleaner, more readable code — especially for patterns like Clone(). But the important thing isn’t which style you choose. It’s that you:
- Understand how the implicit
Recparameter actually works - Make a deliberate decision about which style to use
- Stay consistent — don’t mix styles on the same object
Both approaches produce identical results at runtime. The difference is purely in how the code reads — and that’s exactly what syntactic sugar is all about.