What if two variables are called the same? Or how about a function and variable with the same name? In this video, I take a look at scoping in AL. Check it out:

In this video, Erik explores a subtle but important concept in AL development for Business Central: variable scoping and name resolution. What happens when you name a variable the same as a built-in function like CompanyName? The answer might surprise you — and it’s exactly the kind of mistake that can silently break your code.
The Starting Point: Built-in Functions Without Parentheses
AL has an interesting quirk inherited from its origins in C/AL: when a procedure has no parameters, you don’t need to include the parentheses when calling it. This means that CompanyName and CompanyName() are both valid ways to call the built-in function that returns the current company name.
This made sense historically — in old AL (C/AL), there wasn’t really a difference between a global constant and a function call. We all got used to writing things like Record.Insert without parentheses. But this flexibility opens the door to a scoping problem.
The Setup: Shadowing a Built-in Function
Erik starts with a simple page extension and demonstrates how things go wrong step by step. Here’s the final code that illustrates the scoping issue:
pageextension 50100 CustomerListExt extends "Customer List"
{
trigger OnOpenPage()
begin
Message('This is %1', CompanyName());
Test2();
end;
procedure Test2()
begin
CompanyName := 'Global Var';
Message('This is %1', CompanyName);
Test();
end;
procedure Test()
var
CompanyName: Text;
Today: Date;
begin
Today := 20230101D;
CompanyName := 'Local Var';
Message('Today'' date is %1', Today);
end;
var
CompanyName: Text;
}
How Name Resolution Works in AL
When the AL compiler encounters a name like CompanyName, it resolves it by searching from the innermost scope outward:
- Local variables — variables declared in the current procedure’s
varsection - Global variables — variables declared at the object level
- Built-in functions and symbols — system-provided functions like
CompanyName()
This means that as soon as you declare a global variable called CompanyName, every unqualified reference to CompanyName in that object now refers to your variable — not the built-in function. The built-in function is effectively “shadowed.”
What Each Message Shows
When you run the code above, you see three messages:
- “This is Cronus Canada Incorporated” — In
OnOpenPage,CompanyName()with explicit parentheses still calls the built-in function, even though a global variable with the same name exists. - “This is Global Var” — In
Test2,CompanyNamewithout parentheses resolves to the global variable, which has been assigned the value ‘Global Var’. - “Today’s date is 01/01/2023” — In
Test, the local variableTodayshadows the built-inTodayfunction, so it shows the hardcoded date rather than the current date.
The Parentheses Escape Hatch
One key takeaway: you can always reach the built-in function by explicitly using parentheses. Writing CompanyName() forces the compiler to treat it as a function call, bypassing any variable with the same name. But this is a workaround, not a best practice.
Can You Access the Shadowed Global Variable from a Local Scope?
Erik also experiments with whether you can reach a global variable that’s been shadowed by a local variable of the same name. In the case of a page extension, you can use the protected var modifier and reference it through CurrPage, but in general, once a local variable shadows a global one, the global is inaccessible within that procedure.
What About Other Built-in Functions?
Erik tests a couple of other scenarios:
Format— Creating a variable calledFormatwon’t cause as much trouble becauseFormatalways requires parameters, so the compiler can distinguish between the variable and the function call.Today— This one is dangerous, just likeCompanyName. The built-inTodayfunction takes no parameters, so a variable namedTodaywill completely shadow it. In the demo, the localTodayvariable holds20230101Dinstead of the actual current date.
The Lesson: Don’t Get Clever with Scoping
Erik is candid about how this video came about: he made this exact mistake himself. He created a variable called CompanyName somewhere in his code, and it caused subtle bugs. Everything appeared to work, but the built-in function was being silently replaced by the variable. He had to go back and add parentheses in several places to get things working correctly.
The takeaways are clear:
- Don’t name variables after built-in functions. Even if AL allows it, it creates confusing, error-prone code.
- Be aware of AL’s scope resolution order: local → global → built-in.
- Use parentheses explicitly when calling parameterless functions if there’s any chance of ambiguity.
- Pay attention to syntax highlighting in VS Code — Erik noticed the color change when the identifier switched from a function call to a variable reference, which is a helpful visual cue.
Scoping bugs are particularly insidious because the code compiles and runs without errors — it just doesn’t do what you expect. Learn from Erik’s mistake and keep your variable names distinct from built-in function names.