The X++ language belongs to the “curly brace” family
of programming languages (those that use curly braces to delimit syntax
blocks), such as C, C++, C#, and Java. If you’re familiar with any of
these languages, you won’t have a problem reading and understanding the
X++ syntax.
Unlike many programming
languages, X++ is not case-sensitive. However, using camel casing
(camelCasing) for variable names and Pascal casing (PascalCasing) for
type names is considered a best practice. (More best practices for
writing X++ code are available in the Microsoft Dynamics AX 2009 SDK.)
You can use the Source Code Titlecase Update tool (accessed from the
Add-Ins submenu in the AOT) to automatically apply casing in X++ code to
match the best practice recommendation.
CLR types, which are
case-sensitive, are one important exception to the casing guidelines.
Variable Declarations
You must place variable declarations at the beginning of methods. Table 1
provides examples of value type and reference type variable
declarations, as well as example variable initializations.
Table 1. X++ Variable Declaration Examples
Type | Examples |
---|
anytype | anytype type = null; anytype type = 1;
|
record types | common record = null; CustTable custTable = null;
|
object types | object obj = null; MyClass myClass = new MyClass(); System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
boolean |
|
int |
|
int64 | int64 i = -5; int64 h = 0xAB; int64 u = 0xA0000000u;
|
real | real r1 = 3.14; real r2 = 1.0e3;
|
date |
|
utcdatetime | utcdatetime dt = 2008-12-31T23:59:59;
|
timeofday |
|
str | str s1 = "a string"; str s2 = 'a string'; str 40 s40 = "string 40";
|
guid |
|
container | container c1 = ["a string", 123]; container c2 = connull();
|
base enumeration types | NoYes theAnswer = NoYes::Yes;
|
extended data types |
|
Declaring variables with
the same name as their type is a common practice. At first glance, this
approach might seem confusing. Consider this class and its getter/setter
method to its field.
Class Person { Name name;
public Name Name(Name _name = name) { ; name = _name; return name; } }
|
Because X++ is not case-sensitive, the word name
is used in eight places in the preceding code. Three refer to the
extended data type, four refer to the field, and one refers to the
method (“_name” is used twice). To improve readability, you could rename the variable to something more specific, such as personName.
However, using a more specific variable name implies that a more
specific type should be used (and created if it doesn’t already exist).
Changing both the type name and the variable name to PersonName wouldn’t improve readability. The benefit of this practice is that if you know the name of a variable, you also know its type.
Because X++ allows you
to define variables with the same name as their type, variable names can
become ambiguous. The X++ compiler expects methods to start with
variable declarations. To denote a variable with an ambiguous name and
not a type, you must add a hanging semicolon, as shown in the preceding
example, to signify the end of variable declarations. Including the
hanging semicolon is considered a best practice because it allows your
code to easily accommodate new types. Variable names could become
ambiguous when new extended data types are created, causing compilation
errors.
Expressions
X++ expressions are sequences of operators, operands, values, and variables that yield a result. Table 2 summarizes the types of expressions allowed in X++ and includes examples of their use.
Table 2. X++ Expression Examples
Category | Examples |
---|
Object creation operators | new MyClass() //X++ object creation new System.DateTime() //CLR object wrapper and //CLR object creation new System.Int32[100]() //CLR array creation
|
Values and variables |
|
Access operators | this //Instance member access element //Form member access <datasource>_ds //Form data source access x.y //Instance member access E::e //Enum access a[x] //Array access [v1, v2] = c //Container access Table.Field //Table field access Table.(FieldId) //Table field access (select statement).Field //Select result access System.Type //CLR namespace type access System.DayOfWeek::Monday //CLR enum access
|
Method invocations | super() //Base member invocation MyClass::m() //Static member invocation myObject.m() //Instance member invocation this.m() //This instance member invocation myTable.MyMap::m(); //Map instance member invocation f() //Built-in function call
|
Arithmetic operators | x = y + z // Addition x = y - z // Subtraction x = y * z // Multiplication x = y / z // Division x = y div z // Integer division x = y mod z // Integer division remainder
|
Shift operators | x = y << z // Shift left x = y >> z // Shift right
|
Relational operators | x < y // Less than x > y // Greater than x <= y // Less than or equal x >= y // Greater than or equal x == y // Equal x != y // Not equal select t where t.f like "a*" // Select using wildcards
|
Logical operators | if (!obj) // Logical NOT if (a && b) // Logical AND if (a || b) // Logical OR
|
Bitwise operators | x = y & z // Bitwise AND x = y | z // Bitwise OR x = y ^ z // Bitwise exclusive OR (XOR) x = ~z // Bitwise complement
|
Conditional operators |
|
String concatenation |
|
Parentheses |
|