Understanding "'const' at top level, which may reduce code readability without improving const correctness"

Viewed 2729

Please consider the code below, in particular, observing that get_length returns const size_t.

#include <stdio.h>

const size_t get_length(void)
{
    return 123;
}

void foo(void)
{
    size_t length = get_length();
    length++;
    
    printf("Length #1 is %zu\n", length);
}

void bar(void)
{
    // Still 123 because length was copied from get_length
    // (copy ellision notwithstanding, which is not the point here)
    size_t length = get_length();
    
    printf("Length #2 is %zu\n", length);
}

int main(void) {
    foo();
    bar();
}

Output:

Length #1 is 124
Length #2 is 123

I am getting the following warning from clang-tidy:

Clang-Tidy: Return type 'const size_t' (aka 'const unsigned long')
is 'const'-qualified at the top level,
which may reduce code readability without improving const correctness

This message has two parts about the return type:

  • Const correctness is not improved
  • Code readibility is reduced

I understand the first part where, like in foo and bar, as the callers are not required to specify their local variables as const, ultimately const correctness is not improved, i.e. there is nothing preventing the callers from ignoring the fact that the callee returns a const object.

But I am not sure what is meant by "code readability is reduced" - is that simply because it may give some people false expectations that the return type shall never be modified? Or is there something else to it that only starts to make sense with more complex return types?

I ask because I do not consider readability to be reduced here and I am just not sure what the intention could have been behind the warning. Thanks.

2 Answers

You are allowed to use const there, but Clang-Tidy is also correct in flagging it as ineffective.

The related Q&As under Should useless type qualifiers on return types be used, for clarity?, Benefits of using “const” with scalar type? cover the part of why const is ineffective in this context.

The other part of the question about why "code readability is reduced", that's because a superfluous const qualifier can potentially distract from the core fact that const'ness is not carried over value assignments. It could, for example, tempt the client code into mistakenly believing that the return value must be used a const as well e.g. const size_t val = get_length(); which is not true, as the posted code shows.

A similar caveat goes for arguments. Suppose the return value of const size_t get_length(); is always passed to another function baz(get_length());. The argument of baz needs not (and arguably should not) be declared as const size_t but just plain size_t i.e. void baz(size_t);.

1. Const correctness is not improved

The returned value can only be used as a rvalue. There is no possibility to change a rvalue, so const correctness is already given.

2. Code readability is reduced

You are leading the reader into false assumptions.

Examples

/* the rest of your example... */

void baz(void)
{
    size_t length = get_length();
    length += 42;
    
    printf("Length #2 is %zu\n", length);
}

There is nothing to prevent the change of length. It gets initialized by a constant, right, like size_t length = 123;

/* the rest of your example... */

void fu(void)
{
    const size_t length = get_length();
    length += 42; /* will give a compile-time error */
    
    printf("Length #2 is %zu\n", length);
}
Related