Sometimes you fall over a features in the AL language that see so little use that it’s forgotten by… well, at least me. Check out the video:

In this video, Erik shares a fun discovery he made while writing AL code — he accidentally named a codeunit “XOR” and was surprised when it wouldn’t compile. The reason? xor is actually a reserved keyword in AL! This led him down a rabbit hole exploring the exclusive or (XOR) logical operator, how it works, and where it’s actually used in the Business Central base application.
The Accidental Discovery
Erik was working on implementing bitwise XOR operations in AL — something that’s commonly used in encryption and hashing algorithms. He created a codeunit and named it “XOR,” only to be greeted by a confusing compile error: “End expected.”
Then it dawned on him — look at the syntax coloring. xor is a reserved keyword in AL because it’s a built-in logical operator. He’d simply forgotten about it because he uses it so rarely in everyday Business Central development.
Of course, the fix was simple — just rename the codeunit. But the real story here is about the xor operator itself and how it can be useful in AL development.
What Is XOR?
XOR, or “exclusive or,” is a logical operator that returns true when one but not both of its operands are true. You can think of it as: “either one or the other, but not both.”
The Truth Table
Erik walks through all four possible combinations of boolean inputs to demonstrate how XOR behaves compared to the more familiar and operator:
| A | B | A and B |
A xor B |
|---|---|---|---|
| true | true | true | false |
| true | false | false | true |
| false | true | false | true |
| false | false | false | false |
The key difference: with and, both must be true. With xor, exactly one must be true.
A Real-World Example from the Base App
Erik searched the Business Central base application and found that xor is used approximately 44 times. He highlights a particularly elegant example from the CRM Sync Conflict Buffer table.
The function IsOneRecordDeleted deals with synchronization between CRM and Business Central. When you have a record that existed in both systems, one of them might get deleted. The question is: has exactly one record been deleted?
The logic is straightforward with XOR: if RecordExists xor IntegrationRecordExists evaluates to true, then one record exists and the other doesn’t — meaning exactly one has been deleted. This is a textbook use case for the XOR operator, and it reads much more cleanly than the alternative of writing out compound boolean expressions with and, or, and not.
Bitwise XOR: What Erik Was Actually Building
While the logical xor operator exists natively in AL, bitwise XOR operations do not. This is what Erik was actually working on — implementing bitwise operations for use in hashing algorithms. Here’s his implementation of an FNV hash function that includes a custom BitwiseXor procedure:
pageextension 50135 CustomerListExt extends "Customer List"
{
trigger OnOpenPage();
begin
message('FNV Result = %1 (should be 2267144173)',
FNVHash('jdfgsdhfsdfsd 6445dsfsd7fg/*/+bfjsdgf%$^'));
end;
local procedure FNVHash(str: Text): BigInteger
var
fnv_prime: BigInteger;
wrap: BigInteger;
i: Integer;
hash: BigInteger;
c: Byte;
begin
fnv_prime := 2166136261L; // 0x811C9DC5;
wrap := power(2, 32);
for i := 1 to strlen(str) do begin
hash *= fnv_prime;
if Hash > wrap then
Hash := hash mod wrap;
c := str[i];
hash := BitwiseXor(hash, c);
end;
exit(hash);
end;
local procedure BitwiseXor(A: BigInteger; B: BigInteger): BigInteger
var
Result: BigInteger;
BitMask: BigInteger;
BitIndex: Integer;
MaxBitIndex: Integer;
begin
BitMask := 1;
Result := 0;
MaxBitIndex := 32;
for BitIndex := 1 to MaxBitIndex do begin
if (A mod 2) <> (B mod 2) then
Result += BitMask;
A := A div 2;
B := B div 2;
if BitIndex < MaxBitIndex then
BitMask += BitMask;
end;
exit(Result);
end;
}
How the BitwiseXor Procedure Works
Since AL doesn't have native bitwise operators, Erik implements XOR at the bit level using arithmetic:
- Iterate through each bit position (up to 32 bits for a 32-bit integer)
- Extract the least significant bit of both numbers using
mod 2 - Compare the bits: if they differ (
(A mod 2) <> (B mod 2)), that's exactly the XOR condition — add the current bit mask to the result - Shift both numbers right by dividing by 2 (
A div 2) - Shift the bit mask left by doubling it (
BitMask += BitMask)
This is then used in the FNV (Fowler–Noll–Vo) hash function, a well-known non-cryptographic hash algorithm that relies on multiplication and XOR operations to produce a hash value from a string input.
Conclusion
The xor operator has been part of the AL language for a long time, but it's easy to forget about because it's so rarely needed in typical business logic. However, when you do need it — like checking if exactly one of two conditions is true — it provides a clean and readable solution. The CRM sync example from the base app is a perfect illustration of this.
And while AL supports logical xor natively, it still lacks built-in bitwise operations. For scenarios like hashing and encryption, you'll need to roll your own implementations, as Erik demonstrated with his BitwiseXor procedure. Perhaps one day Business Central will add native bitwise operators to AL — but until then, arithmetic and modular math get the job done.