Programming in D – Tutorial and Reference
Ali Çehreli

Other D Resources

const ref Parameters and const Member Functions

This chapter is about how parameters and member functions are marked as const so that they can be used with immutable variables as well. As we have already covered const parameters in earlier chapters, some information in this chapter will be a review of some of the features that you already know.

Although the examples in this chapter use only structs, const member functions apply to classes as well.

immutable objects

We have already seen that it is not possible to modify immutable variables:

    immutable readingTime = TimeOfDay(15, 0);

readingTime cannot be modified:

    readingTime = TimeOfDay(16, 0);    // ← compilation ERROR
    readingTime.minute += 10;          // ← compilation ERROR

The compiler does not allow modifying immutable objects in any way.

ref parameters that are not const

We have seen this concept earlier in the Function Parameters chapter. Parameters that are marked as ref can freely be modified by the function. For that reason, even if the function does not actually modify the parameter, the compiler does not allow passing immutable objects as that parameter:

/* Although not being modified by the function, 'duration'
 * is not marked as 'const' */
int totalSeconds(ref Duration duration) {
    return 60 * duration.minute;
}
// ...
    immutable warmUpTime = Duration(3);
    totalSeconds(warmUpTime);    // ← compilation ERROR

The compiler does not allow passing the immutable warmUpTime to totalSeconds because that function does not guarantee that the parameter will not be modified.

const ref parameters

const ref means that the parameter is not modified by the function:

int totalSeconds(const ref Duration duration) {
    return 60 * duration.minute;
}
// ...
    immutable warmUpTime = Duration(3);
    totalSeconds(warmUpTime);    // ← now compiles

Such functions can receive immutable objects as parameters because the immutability of the object is enforced by the compiler:

int totalSeconds(const ref Duration duration) {
    duration.minute = 7;    // ← compilation ERROR
// ...
}

An alternative to const ref is in ref. As we will see in a later chapter, in means that the parameter is used only as input to the function, disallowing any modification to it.

int totalSeconds(in ref Duration duration) {
    // ...
}
Non-const member functions

As we have seen with the TimeOfDay.increment member function, objects can be modified through member functions as well. increment() modifies the members of the object that it is called on:

struct TimeOfDay {
// ...
    void increment(in Duration duration) {
        minute += duration.minute;

        hour += minute / 60;
        minute %= 60;
        hour %= 24;
    }
// ...
}
// ...
    auto start = TimeOfDay(5, 30);
    start.increment(Duration(30));          // 'start' gets modified
const member functions

Some member functions do not make any modifications to the object that they are called on. An example of such a function is toString():

struct TimeOfDay {
// ...
    string toString() {
        return format("%02s:%02s", hour, minute);
    }
// ...
}

Since the whole purpose of toString() is to represent the object in string format anyway, it should not modify the object.

The fact that a member function does not modify the object is declared by the const keyword after the parameter list:

struct TimeOfDay {
// ...
    string toString() const {
        return format("%02s:%02s", hour, minute);
    }
}

That const guarantees that the object itself is not going to be modified by the member function. As a consequence, toString() member function is allowed to be called even on immutable objects. Otherwise, the struct's toString() would not be called:

struct TimeOfDay {
// ...
    // Inferior design: Not marked as 'const'
    string toString() {
        return format("%02s:%02s", hour, minute);
    }
}
// ...
    immutable start = TimeOfDay(5, 30);
    writeln(start);    // TimeOfDay.toString() is not called!

The output is not the expected 05:30, indicating that a generic function gets called instead of TimeOfDay.toString:

immutable(TimeOfDay)(5, 30)

Further, calling toString() on an immutable object explicitly would cause a compilation error:

    auto s = start.toString(); // ← compilation ERROR

Accordingly, the toString() functions that we have defined in the previous chapter have all been designed incorrectly; they should have been marked as const.

Note: The const keyword can be specified before the definition of the function as well:

    // The same as above
    const string toString() {
        return format("%02s:%02s", hour, minute);
    }

Since this version may give the incorrect impression that the const is a part of the return type, I recommend that you specify it after the parameter list.

inout member functions

As we have seen in the Function Parameters chapter, inout transfers the mutability of a parameter to the return type.

Similarly, an inout member function transfers the mutability of the object to the function's return type:

import std.stdio;

struct Container {
    int[] elements;

    inout(int)[] firstPart(size_t n) inout {
        return elements[0 .. n];
    }
}

void main() {
    {
        // An immutable container
        auto container = immutable(Container)([ 1, 2, 3 ]);
        auto slice = container.firstPart(2);
        writeln(typeof(slice).stringof);
    }
    {
        // A const container
        auto container = const(Container)([ 1, 2, 3 ]);
        auto slice = container.firstPart(2);
        writeln(typeof(slice).stringof);
    }
    {
        // A mutable container
        auto container = Container([ 1, 2, 3 ]);
        auto slice = container.firstPart(2);
        writeln(typeof(slice).stringof);
    }
}

The three slices that are returned by the three objects of different mutability are consistent with the objects that returned them:

immutable(int)[]
const(int)[]
int[]

Because it must be called on const and immutable objects as well, an inout member function is compiled as if it were const.

How to use