Work with identifiers, syntax, and variables

Completed

Before you can start working with variables and functions, you first need to learn some important concepts. Identifiers, syntax, and variables are central concepts of AL and other programming languages.

An identifier is the name of a programming element, while a variable is a location in memory where data is stored. You can use an identifier to give your variable a name so that you can use it.

Syntax describes the grammatical rules for using these identifiers. The syntax of the identifiers is determined by the application language and some best practices.

A few grammatical rules are in place for using identifiers. Within one object, all identifiers must be unique. Therefore, within one object, you can't declare two variables with the same identifier (or name).

When you are defining a variable by an identifier, the first character is preferably an underscore or a letter. When you use a special character or a space in the identifier, you must enclose the identifier with double quotation marks.

Though application language is not case-sensitive, it does not differentiate between upper and lowercase letters in identifiers. We recommend that you create identifiers with PascalCase. PascalCase means that you start the name of your variable with an uppercase letter. If your name is combination of two words, you would start the second word with an uppercase letter as well. For example, if you have a variable for storing a customer's name, you can use CustomerName, which is an example of PascalCase notation.

Before working with variables, you need to declare them, which means that the variables must:

  • Have an identifier

  • Have a scope

  • Have a data type

  • Be initialized

Your variable also needs to have a scope, which defines where you can access and use your variable.

A variable can be defined with a global or a local scope. If you define your variable with a global scope, your variable will be available everywhere in the object. Therefore, on every trigger, everywhere you want to write some code statements, you will have that variable available. When the scope is local, you can only access that variable in the specific trigger in the procedure where it was declared.

Example of Global and Local scope variables.

In the preceding example, the variable Counter is declared with a global scope, and it can be used in every trigger and function in the table MyTable. The variable CustomerName is defined in the OnInsert trigger; therefore, it has a local scope. The variable can only be used in this trigger and can't be called from another trigger. Defining all your variables with a global scope can be easier, but then this variable can be used in every trigger. The variable can then be changed within every trigger, which can lead to unwanted or unsuspected results. Accordingly, when you are declaring variables, think about the scope definition and then choose the correct one.

System-defined variables that are automatically defined and maintained by the system also exist, and their scope is also set by the system. The Rec and xRec variables are examples of system-defined variables. Rec gives access to the current record, and xRec gives access to the previous record (for example before an update occurred).

A variable always has a certain data type. It could be an integer, a text, a code, a date, an option, and so on. When a variable is created in memory, it is initialized, meaning that the variable gets a default starting value before you assign a value to this variable. This default value depends on the data type of that variable.

For variables with a numeric data type, a value of zero will be used to initialize. String variables will be initialized with an empty string. A Boolean variable has a default value of false.

Until recently, each variable had to be declared on its own line. In larger objects, this led to pages of variable declarations, even if most of these were of the same type.

To reduce scrolling, improve readability, and make it easier to see and declare related types, it's now possible to add multiple variable declarations of the same type in a singular line.

Declare multiple variables of the same type in the same line, using a comma to separate variable names.

For example:


var
        myInt, nextInt, thirdInt : Integer;
        isValid, doCheck : Boolean;

Protected Variables

The protected keyword can be used to make variables accessible between tables and table extensions and between pages and page extensions.

If you want to only expose some variables as protected, you must create two sections of var declarations. See the syntax below.


protected var
        myInt: Integer; // protected var

var
        myLocalInt: Integer; // local var

The example below illustrates how to declare and use a protected variable.


page 50100 MyPage
{
    SourceTable = Customer;
    PageType = Card;

    layout
    {
        area(Content)
        {
            group(General)
            {
                field(Name; Name)
                {
                    ApplicationArea = All;
                }
            }
            group(Advanced)
            {
                Visible = ShowBalance;

                field(Balance; Balance)
                {
                    ApplicationArea = All;
                }
            }
        }
    }

    protected var
        [InDataSet]
        ShowBalance: Boolean;
}

pageextension 50101 MyPageExt extends MyPage
{
    layout
    {
        addlast(Content)
        {
            group(MoreBalance)
            {
                Visible = ShowBalance; // ShowBalance from MyPage

                field("Balance (LCY)"; "Balance (LCY)")
                {
                    ApplicationArea = All;
                }
            }
        }

    }

    actions
    {
        addlast(Navigation)
        {
            action(ToggleBalance)
            {
                ApplicationArea = All;
                trigger OnAction()
                begin
                    ShowBalance := not ShowBalance; // Toggle ShowBalance from MyPage.
                end;
            }
        }
    }
}

Guidelines for placing AL code

We recommend the following guidelines for AL code:

  • In general, write the code in codeunits instead of on the object on which it operates. This promotes a clean design and provides the ability to reuse code. It also helps enforce security. For example, typically users don't have direct access to tables that contain sensitive data, such as the General Ledger Entry table, nor do they have permission to modify objects.

  • If you put the code that operates on the general ledger in a codeunit, give the codeunit access to the table, and give the user permission to run the codeunit, then you won't compromise the security of the table and the user will be able to access the table.

  • If you must put code on an object instead of in a codeunit, then put the code as close as possible to the object on which it operates. For example, put code that modifies records in the triggers of the table fields.

Reusing code

Reusing code makes developing applications both faster and easier. More importantly, if you organize your AL code as suggested, your applications will be less prone to errors. By centralizing the code, you won't unintentionally create inconsistencies by performing the same calculation in many places, for example, in several triggers that have the same table field as their source expression. If you have to change the code, you could either forget about some of these triggers or make a mistake when you modify one of them.