Basic operators

This section is a whirlwind tour of the basic operators D supports. For the most part, things are the same as they are in C. There are a few minor differences that will be highlighted as we come to them. More operators will appear later in this chapter and throughout the book. You can read more about D's operators at http://dlang.org/expression.html.

Arithmetic operators

All of the common arithmetic operators are available: +, -, *, / and %, representing addition, subtraction, multiplication, division, and modulus respectively. Additionally, D has an exponentiation operator, ^^, which raises the left operand to an exponent (power) represented by the right operand. For example, 22 can be expressed as 2 ^^ 2.

D also supports the standard increment and decrement operators. In the prefix form (++x and --x), the result of the expression is the new value. In the postfix form (x++ and x--), the result is the original value of the operand. To be more explicit, under the hood D is doing something like this for the prefix version:

x = x + 1;
return x;

And this for the postfix version:

auto temp = x;
x = x + 1;
return temp;

In the postfix form, if the resulting value is never used, then the compiler can optimize temp away and it will effectively be the same as the prefix version. For example:

int x = 2;
x++;   // Identical to ++x – no temporary

Like C++, D allows the increment and decrement operators to be overloaded by custom types. Unlike C++, D guarantees that the temporary variable in a postfix expression can always be optimized away when it isn't needed, even if the operand is a user-defined type. Even so, it's considered best practice to use the prefix form unless the behavior of the postfix expression is desired.

Bitwise operators

I assume you already know that there are eight bits in a byte, that bits can be 1 or 0, and that bitwise operators can be used to selectively turn bits on or off, reverse their state, or move them around. D supports the binary bitwise operators &, |, and ^, representing binary AND, OR, and XOR, and the unary operator ~, representing the one's complement. The left and right shift operators, << and >>, are also supported.

Additionally, D has the unsigned right shift operator, >>>. Anyone with a Java background will be familiar with this. When the left operand is an unsigned type, >> and >>> behave identically. When operating on a signed type, the right shift operator, >>, preserves the sign bit. This means that right shifting a positive value will yield a positive value and right shifting a negative value produces a negative value. The unsigned right shift operator treats the sign bit as any other bit and does not preserve it. Essentially, it's the same as casting the signed type to an unsigned type and performing a right shift.

int a = -3;        
writeln(a >> 4);            // -1
writeln(a >>> 4);           // 268_435_455       
writeln(cast(uint)a >> 4);  // 268_435_455

You've already learned about the assignment operator, =. Although the same operator is used for both assignment and initialization, the language does make a distinction when overloading operators on user-defined types. Additionally, all of the binary arithmetic operators and the bitwise operators have compact forms, referred to as opAssign operators, that store the result of the expression in the left operand. These are +=, -=, *=, /=, %=, ^^=, &=, |=, ^=, <<=, >>= and >>>=.

Relational and logical operators

Relational operators determine the relationship between two operands in terms of equality and ordering (greater than and less than). Relational expressions evaluate to true or false. D supports the same relational operators found in other C-family languages: ==, !=, <, >, <=, >=, representing equal, not equal, less than, greater than, less than or equal, and greater than or equal. Due to the potential for rounding errors and the existence of special values such as NaN and infinity, floating-point comparisons can be tricky. The Phobos module std.math provides functions such as isIdentical, isInfinity, isNaN, and approxEquals to help.

The binary is operator is similar to the equality operator ==. More technically, x is y is referred to as the identity expression. For value types, this is usually the same as x == y, though this isn't always true for floating point values and struct instances. For example:

float f;            // Initialized to float.nan
writeln(f == f);    // false
writeln(f is f);    // true

Instances of a struct type that has overridden the equality operator will usually cause == and is to produce different results. Otherwise, the default behavior of struct equality is the same as is, which is to make a bit-by-bit comparison (structs are introduced in Chapter 3, Programming Objects the D Way, and operator overloading in Chapter 5, Generic Programming Made Easy). The difference between == and is becomes most apparent when working with reference types, as we'll observe later.

Logical operators produce true or false. For anyone with C-family experience, there is nothing special or surprising about them in D: x && y evaluates to true if both operands are true; x || y evaluates to true if either operand is true; !x evaluates to true if the operand is false.

The cast operator

The cast operator converts a variable from one type to another. It looks like this:

auto y = cast(T)x;

Here, T represents the type to which x is cast. If the cast is not legal, the compiler will emit an error. The traditional C-style cast, which is (T) without the cast keyword, is not supported. Additionally, D does not support multiple cast operators for different types of casts as C++ does. Though, as we'll see in the next chapter, D's cast has a special feature when x is a class instance and T is a class or interface.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.122.127