Menu

Syntax-Expressions

Ove Kåven

Operators

Most built-in operators follow C/C++ syntax, though sometimes alternatives are available. Many operators can be overloaded. That is, structs and classes can often freely define what happens when you use a particular operator on them.

Currently, operator precedence, from highest to lowest, are:

Precedence Associativity Operator Overloadable Description
Special None |...| Yes Absolute value (NIY)
||...|| Yes Length (NIY)
1 Left . See note 1 Member reference
?. See note 1 Null-safe member reference
??. See note 1 Auto-allocating member reference
(...) Yes (NIY) Call
[...] See note 2 Index
2 Right @ No Metaexpression
* No Expansion (NIY)
3 Left <...> No Generic type argument
4 Right (:...) No Static typecast
ref No Reference of
sizeof No (Static) Size of
typeid Yes (Dynamic) Type ID of
5 Left as No Dynamic typecast
6 Left ! Yes Factorial (NIY)
~ Yes Inverse (NIY)
++ Yes Post-increment
-- Yes Post-decrement
7 Right ^ Yes Power (NIY)
8 Right + Yes Copy
- Yes Negation
~ Yes Bitwise NOT
++ Yes Pre-increment
-- Yes Pre-decrement
9 Left * Yes Multiplication (inner product, matrix product)
** Yes Multiplication (cross product) (NIY)
>< Yes Multiplication (outer product) (NIY)
/ Yes Right division
\ Yes Left division (NIY)
% Yes Remainder
*. Yes Elementwise multiplication (NIY)
/. Yes Elementwise right division (NIY)
\. Yes Elementwise left division (NIY)
div Yes Euclidean division (NIY)
mod Yes Modulo (NIY)
10 Left + Yes Addition
- Yes Subtraction
11 Left << Yes Bit shift left
>> Yes Bit shift right
12 Left & Yes Bitwise AND
13 Left <> Yes Bitwise XOR
14 Left | Yes Bitwise OR
15 Left ?? No Null coalescing
16 None :: No Slice
.. No Range
17 None == Yes Equal to
!= Yes Not equal to
=== No Alias of
!== No Not alias of
< Yes Less than
> Yes Greater than
<= Yes Less than or equal to
>= Yes Greater than or equal to
<=> Yes Combined comparison
~= Yes Pattern match (NIY)
in Yes Contained in
not in Yes Not contained in
is See note 3 (Dynamic) Derived type of
is not See note 3 (Dynamic) Not derived type of
18 Right !, not Yes Logical NOT
19 Left &&, and Yes Logical AND
20 Left ||, or Yes Logical OR
21 Right ? : No Conditional
22 Right -> No Anonymous function (NIY)
23 Right := See note 4 Inline assignment
<<< Yes Receive (NIY)
>>> Yes Send (NIY)
24 None throw No Throw exception

Notes:
1. The member reference operator itself cannot be overloaded, but references to certain member names can be converted to method calls by defining the members as properties. It's under consideration whether to allow redirecting references to unknown member names to some fallback method (where compilation error would otherwise result).
2. References to indexes can be converted to method calls by defining indexers. Indexers can be overloaded.
3. While the is operator can be overloaded, is null and is not null is exempt from any overloading, and can thus be used as a reliable way of checking if a reference is null.
4. Overloads of ordinary assignments also apply to inline assignments.

Members and dereferences

The period, ., is used to refer to named members of objects, classes, namespaces, etc. For example, if universe is a reference to an object with an instance variable called answer, then you can say

universe.answer = 42

Following a reference in order to access the actual object is called dereferencing. Referencing and dereferencing is automatic, but depends on the types used (thus, typecasts affect the way this is done).

However, if an object reference is null (doesn't refer to anything), and the member is not static, then doing the above unconditionally will probably cause problems (most likely crash). If you're dealing with nullable references, then you'll usually have to explicitly check for null, but some operators are available to make the job easier.

  • To explicitly check for null, the recommended way is to use either is null or === null, since these constructs cannot be overloaded.
  • The null coalescing operator ?? (as seen in C#) allows you to substitute another object when the one you want is null. In the expression a ?? b, a is used if it's non-null, otherwise b is used.
  • The null-safe member reference operator ?. (as seen in Groovy) only follows the reference if it is not null. If it is null, then the expression (data access or method call) evaluates to the default value for the inferred expression type, usually null or zero. In the expression car?.drive(), the drive method is only called if car isn't a null reference.
  • As a special case, if the null-safe member reference operator is used on an allocator, then it is invoked if the reference is null. In the expression car?.new(), a new car object is allocated and assigned to car if it was null before this.
  • The auto-allocating member reference operator ??. will, if the reference is null, allocate a new object of the required type and assign it to the reference. Then it follows the reference as normal. In the expression car??.drive(), a new car object is allocated (using the default allocator) and assigned to car if it was null, and then the drive method is called, regardless of whether car was previously null or not.

Calls

To call a function, method, or delegate, enclose its arguments in parentheses after its name (or other reference to it). Even if there are no arguments, the parentheses are necessary. For example,

exit()

calls the exit function with no arguments.

f = fac(2)

calls the fac function with one integer argument, and assigns its return value to the variable called f.

Indexes

Many objects that can contain other objects, such as arrays, support indexed references as a means of referring to a particular contained object. In this case, enclose the index in square brackets after the container reference. For example, if prime_list were an array of prime numbers, then

prime = prime_list[3]

would give you the 3rd prime in this list.

Metaexpressions

Metaexpressions are evaluated at compile time, and can refer to information available to the compiler that wouldn't normally be available at runtime. A simple example is the source code filename (similar to the __FILE__ macro in C/C++). Metaexpressions are useful when used in metamethods, or in implicit parameters to ordinary methods.

The form @expression results in a regular parser token for the compiler. If the expression creates a string, then it is converted to an identifier (a reference to a named object).

The form @#expression results in a string. If the expression refers to an object, then the name of that object is converted to a string.

To manipulate an object's name as a string inside the metaexpression itself, refer to the object's name property, e.g., owner.name. This is useful for constructing new identifiers, e.g., @(owner.name + "Child").

Special information that can be used in metaexpressions include:

Name Type Description
function Function object Enclosing function or method
owner Class object Enclosing class or struct
super Class object Base class or struct
module String Module name
file String Source file name
line Integer Source line number

Related

Wiki: Syntax

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.