Segment AL code and reduce naming conflicts with namespaces

Completed

Namespaces are used to organize code into logical groups and hierarchies, which can prevent naming conflicts that can occur when libraries are combined. Namespaces ensure uniqueness in code names and allow reuse of names in different contexts. Namespaces provide structure for the code base, making it easier to navigate and understand. Namespaces are used in many programming languages and with Business Central they're available with AL.

An AL file declares a namespace at the beginning of the file, and all objects in the code file belong to that namespace. A given object can only belong to one namespace, but the same namespace can be used for multiple AL files, which means for multiple objects and for multiple modules. There are two compiler rules that apply to namespaces and object naming specifically:

  • You can only have one object of a kind with the same name in a module

  • You can only have one object of a kind with the same name in a namespace

Renaming existing object or member names is a breaking change, therefore namespaces can only help with logical structure for existing objects.

Any app that is dependent on your app breaks if you rename namespaces, and likewise your app breaks if any of your dependencies rename their namespaces.

To declare a namespace in AL, you must use the namespace keyword followed by the name of the namespace. Some best practices for namespace keywords are:

  • A namespace should be globally unique.

  • The first part of a namespace is tied to the developing organization or an individual, followed by a product name, and logical grouping within the product, such as, for example, namespace BigCompany.SmartProduct.SomeProductArea. This supports the two purposes of namespaces - object name unique and logical grouping of related functionality.

  • Use a stable and non-version specific name for the namespace. Changing the name of a namespace is a breaking change.

  • The namespace name can be any valid AL identifier, and it can contain dots to indicate a hierarchy of namespaces.

The following example shows the syntax of a namespace declaration. All of the objects declared in the code file belong to the namespace MyNamespace. The syntax shown here is for illustrational purposes, as it's still a best practice to separate objects into different files, and to use the same name for the file as the object. For more information, see Best Practices for AL code.

namespace MyNamespace;

// codeunits, tables, pages....

Now, to refer to the objects in the MyNamespace, you must either use the fully qualified name, or the using directive. For more information, see Using directive.

To declare more objects in the same namespace, you can use the same namespace declaration in other .al files. All code files that use the same namespace declaration belong to the same namespace.

The using directive

To refer to objects in other namespaces, you can either use the fully qualified name, or the using directive. The using directive is used to refer to objects in other namespaces without having to use the fully qualified name. The using directive is placed at the top of the .al file, after the namespace declaration and before any object declarations. The following example shows the order of the namespace declaration and the using directive. The order of the using directives doesn't matter.

namespace MyNamespace;
using SomeOtherNamespace;

codeunit 10 MyCode
  {
    ...
  }

When objects are resolved, they're resolved using the closest scope first. Therefore, to resolve to a similar named object in a dependent extension, the reference must use a fully qualified name. Alternatively, it's possible to define using directives to refer external namespaces and avoid fully qualified names for references to objects in those.

A nested namespace is a namespace that's declared within another namespace. Nested namespaces allow for better and more structured naming of objects compared to having to express the full structure in the 30 character object name. The following syntax shows a nested namespace declaration of MyNestedNamespace within the MyNamespace namespace, separated by a dot.

namespace MyNamespace.MyNestedNamespace;

In the example, the fully qualified name of the namespace is MyNamespace.MyNestedNamespace. To refer to objects in the MyNestedNamespace namespace, you must then use the fully qualified name, or the using directive. So, to be able to access objects that are declared in the MyNestedNamespace, include the following statement in your code:

using MyNamespace.MyNestedNamespace

Use code actions to help add namespaces to existing source. For more information, see Code actions.

Summary

An AL file can define a namespace at the top, which applies to all objects in the code file. A given object can only belong to one namespace, but the same namespace can be used for multiple AL files and objects.

When objects are resolved, the closest scope is used first. Therefore, to resolve to a similarly named object in a dependent extension, the reference must use a fully qualified name. Or you can define it using directives to include external namespaces and omit fully qualifying names.

Because namespaces are useful for logical segmentation of extensions, the AL Explorer also shows namespaces for objects and allows grouping objects by namespace. That makes it easier to discover related objects, focus on app subareas, and identify inconsistencies when adding new objects.

Nested namespaces provide better naming of objects than expressing the full structure in the 30-character object name. However, renaming existing objects is a breaking change, so this capability mainly helps with the logical structure of existing objects and new names going forward.

Here's an example of base app objects grouped by namespace, with Customer table residing in the Microsoft.Sales.Customer namespace. Grouping objects by namespace like this makes it easier to focus on and find related objects.

Screenshot of base app objects grouped by namespace.