views:

863

answers:

13

My co-worker is 0 for 2 on questions he has inspired (1, 2), so I thought I'd give him a chance to catch up.

Our latest disagreement is over the style issue of where to put "const" on declarations.

He is of the opinon that it should go either in front of the type, or after the pointer. The reasoning is that this is what is typically done by everyone else, and other styles are liable to be confusing. Thus a pointer to a constant int, and a constant pointer to int would be respectively:

const int *i;
      int * const i;

However, I'm confused anyway. I need rules that are consistent and easy to understand, and the only way I can make sense of "const" is that it goes after the thing it is modifying. There's an exception that allows it to go in front of the final type, but that's an exception, so it's easier on me if I don't use it.

Thus a pointer to a constant int, and a constant pointer to int would be respectively:

int const * i;
int * const i;

As an added benifit, doing things this way makes deeper levels of indirection easier to understand. For example, a pointer to a constant pointer to int would clearly be:

int * const * i;

My contention is that if someone just learns it his way, they'll have trouble figureing out wth the above works out to.

The ultimate issue here is that he thinks that putting const after int is so unspeakably ugly, and so harmful to readability that it should be banned in the style guide. Of course, I think if anything the guide should suggest doing it my way, but either way we shouldn't be banning one approach.

Edit: I've gotten a lot of good answers, but none really directly address my last paragraph ("The ultimate issue"). A lot of people argue for consistency, but is that so desirable in this case that it is a good idea to ban the other way of doing it, rather that just discouraging it?

+18  A: 

The most important thing is consistency. If there aren't any coding guidelines for this, then pick one and stick with it. But, if your team already has a de facto standard, don't change it!

That said, I think by far the more common is

const int* i;
int* const j;

because most people write

const int n;

instead of

int const n;

A side note -- an easy way to read pointer constness is to read the declaration starting at the right.

const int* i; // pointer to an int that is const
int* const j; // constant pointer to a (non-const) int
int const* aLessPopularWay; // pointer to a const int
rlbond
I disagree with "That said, I think by far the more common is". Otherwise agree.
Martin York
+1 for the read from the right tip.
Alex B
Do you think more people do it the other way? Personally, I've seen const type* much more often.
rlbond
Well - not the most scientific result, however, google code search has 41 results 'int const *' and 824 for 'const int *' (searching with lang:c++)
Richard Corden
@finnw: Take it up with Stroustrup, who does it that way as well. And yes, it is parsed that way, but if you follow the "one declaration per line" rule, it doesn't matter. Moreover, the * with the int emphasizes that the type is an int*. Finally, if you're going to give someone -1 over such a syntactic difference which is widely used by C++ coders, I think you're missing the point of Stack Overflow and abusing your voting power.
rlbond
+1 for the phrase "abusing your voting power"!
Max Lybbert
Consistency is not so important, more important is flexibility and diversity.
nobar
@nobar: Consistency is important when there are 2 identical ways of doing something.
rlbond
@ribond: It appears that we are at odds about consistency and pointers but we agree on one thing: "I like C++." on our "About Me" pages. :)
nobar
@finnw: I always marvel at why people insist that the `*` must be adjacent to anything. Write `int * i;`, and not only will neither of the two "camps" blame you for favoring the other's view, but the chance of anyone overlooking the `*` is actually less than with *either* of the alternatives.
DevSolar
@DevSolar I agree, but I have deleted my original comment because it was messed up by the introduction of comment markup on SO.
finnw
@DevSolar: That's how I do it. Nor do I ever have more than one pointer variable per definition (and darn few cases of any multiple variables per definition).
David Thornley
+2  A: 

Putting "const" after the type declaration makes a whole lot more sense once you train yourself to read your C++ type declarations from right to left.

I'm going to peg your cow-orker at 0-for-3 :)

Not Sure
+5  A: 

People typically use "const int* blah" because it reads well as English. I wouldn't underestimate the usefulness of that.

I find that the "int * const blah" variation is rare enough that it's not typically useful to make the more common definition backwards. I am, in general, not a fan of anything that even slightly obscures code in the general case, though it might provide some nominal benefit in the exceptional case.

See also "if (1 == a)". Some people really enjoy writing code that doesn't read as English. I am not one of those people.

Really, though, the rules behind const are simple. Look to the left, then to the right. So simple that I wouldn't think it's worth much attention in a style guide.

Dan Olson
This issue actually came up in the argument. As an old Ada coder I find it kind of funny. If code not reading well in English is a problem for you, you have no business whatsoever using a C-syntax language. It wasn't designed for English-like readability, and trying to impose same on it is just going to drive you batty.
T.E.D.
As an old C++ coder, I believe that if the small inconsistency in using const on the left side in the common case is a problem for you, you have no business whatsoever using a C-syntax language. It wasn't designed for consistency and trying to impose some on it is just going to drive you batty. Seriously, you and your friend have already wasted more time arguing about it than would be saved by choosing either one of your suggested standardizations. Fire anyone that can't understand both syntaxes and be done with it.
Dan Olson
@T.E.D: I think that's a strawman argument. Just because "perfect" readability isn't possible, we can still strive to make it a bit more readable. In particular, why not make variable declarations look the same way as they're spoken, when we have the option?
jalf
@jalf: We don't have that option. The way you'd say it in English would have the type last (like in Ada). ie: "Blah is a constant integer". How does the above even come close to English? "Constant integer pointer to is blah". Only if you are Yoda. Now that I see it in black-and-white, I think you've managed to talk me into voting down this answer.
T.E.D.
@Dan Olson: Sorry about the late downvote. I suppose there could be a legitimate English sentence that would use that word order as you claim, but I don't see it. If you can edit your answer to include that sentence, I'll remove the downvote.
T.E.D.
How about "I am declaring a constant integer pointer."
Dan Olson
"...named blah". I guess I could take that. Note that you had to use the first person present perfect tense to do it though. Far more awkward than "Blah is a constant integer". But fair is fair. Put that in the answer and I'll take back the downvote (SO won't let me change the vote unless the answer changes)
T.E.D.
Heh. According to Wikipedia what you used is actually the "present continuous", as opposed to my "present simple". I suppose you could make it imperitive by changing it to "Declare a...".
T.E.D.
Yeah, it doesn't matter: "constant integer pointer" reads better to me than "integer constant pointer", but constant can function as both adjective and noun, and integer is incorrectly used as an adjective in both cases (I think). It's a matter of preference, if I have to choose between readability and consistency I'm going to pick readability in this case because I think the loss of clarity due to readability is worse in this case.
Dan Olson
A: 

Personally I (and it is a personal preeference) I finding reading type declarations from right to left the easiest. Especially when you start throwing references into the mix.

std::string const&  name = plop; // reference to const string.

const std::string&  flame =plop; // reference to string const;
                                 // That works better if you are German I suppose :-)
Martin York
rlbond
Personally the english does not read as well (but it works).
Martin York
My coworker happens to know German, so this might be part of the issue. :-)
T.E.D.
+5  A: 

I was at a conference where Bjarne Stroustrup was giving a presentation, and he used something like const int* i; Someone asked him why this style and he responded (paraphrasing): "people like to see const first when something is constant".

Nemanja Trifunovic
Sadly, he didn't apply that principle to the syntax of "const" in the general case, or we wouldn't be having this discussion.
T.E.D.
David Thornley
@David C++ dates from 1983, and the predecessor "C with classes" from the late seventies I think. C++ had const first, it was added to C with C90
Pieter
IIRC, C++ got const after C considered -- end eventually rejected -- "readonly".
Max Lybbert
Bjarne claims that he invented const: http://www.research.att.com/~bs/bs%5Ffaq2.html#constplacement. This article also mentions that Bjarne initially considered "readonly".
nobar
+7  A: 

There's a class of examples where putting the const on the right of the type also helps avoid confusion.

If you have a pointer type in a typedef, then it is not possible to change the constness of the to type:

typedef int * PINT;
const PINT pi;

'pi' still has the type 'int * const', and this is the same no matter where you write the 'const'.

Richard Corden
That's a damn good point.
T.E.D.
I don't think that's so confusing. Your example is a const (int*), since the typedef acts as a grouping -- similar to (int*) const. In contrast, a pointer to const is a (const int)* or an (int const)*
rlbond
Its not confusing if you can look at PINT and say: "It's a typedef therefore the const doesn't apply to the pointed to member, because *I* know that's what the standard says about typedefs.". What if PINT was a macro? Then the rules are different and the CV specifier will apply to the to type. Within reason your code should be clear and as unambiguous as you can make it.
Richard Corden
+3  A: 

The ultimate issue here is that he thinks that putting const after int is so unspeakably ugly, and so harmful to readability that it should be banned in the style guide

Really?

Show me a programmer who gets bogged down when he sees:

int foo() {
}

vs

int foo()
{
}

...and I'll show you a programmer who doesn't pay close enough attention to detail.

No professional programmer worth his salt will have a problem with superficial differences in style.

EDIT: It is true that const int* and int* const don't mean exactly the same thing, but that wasn't the point. The point made by OP's coworker was that differences in style make code difficult to understand & maintain. It is this claim I disagree with.

John Dibling
Show me a programmer who thinks those mean the same thing, and I'll show you a programmer who doesn't pay close enough attention to detail.
David Thornley
True they don't mean the same thing, but that wasn't the argument. The argument was that the difference in style is "so harmful to readability" that it should be outlawed. If you don't like the const int* vs int* const argument, fine. We could extend the conversation to be about curly braces. My claim is that no good programmer will have a problem understanding code because of a style difference. So don't sweat the small stuff.
John Dibling
Actually, the root of the difference is "const int*" vs. "int const *"
T.E.D.
+2  A: 

While there is no meaningful difference between const int and int const (and I've seen both styles in use), there is a difference between const int * and int * const.

In the first, you have a pointer to a const int. You can change the pointer, but you can't change the value it points to. In the second, you have a const pointer to int. You can't change the pointer (hope it's initialized to your liking), but you can change the value of the pointed-to int.

The proper comparison is with const int * and int const *, which both are pointers to a const int.

Remember that the * doesn't necessarily work as you might like. The declaration int x, y; will work as you expect, but int* x, y; declares one pointer to int, and one int.

David Thornley
+1  A: 

Rules are good to follow. Simpler rules are better. Const goes to the right of what's const.

Take this declaration:

int main ( int const argc , char const * const * const argv ) ...

+2  A: 

I hope this explanation from B. Stroustrup's FAQ on Style & Techniques will give you a definite answer.

Bjarne Stroustrup's C++ Style and Technique FAQ

I personaly prefer:

int const* pi;
int* const pi;

Because const identifies the left token which is intended to be const.

And you definitely keep the same consistency when using smth like that:

int const* const pi;

Instead of writing inconsistently:

const int* const pi;

And what happens if you have a pointer to pointer and so on:

int const* const* const pi;

Instead of:

const int* const* const pi;

Regards,

Ovanes

ovanes
A: 

I like to to use the following form for declaring "manifest constants". In this case, the value itself is a constant.

const int i = 123;

For declaring references which will not be used to modify the value, I use the following form which emphasizes the fact that the identifier is a "constant reference". The referenced value may or may not be a constant.

void fn( int const & i );

For pointers, I use the same form that I use for references, for essentially the same reason (although the term "constant pointer" seems a little more ambiguous than "constant reference").

void fn( int const * i );

Also, as another poster noted, this form remains consistent when you have multiple levels of indirection.

void fn( int const * const * i );

The final scenario, where you are declaring a pointer which is constant is pretty rare in my experience with C++. In any case, you don't really have any choices here.

void fn( int * const i );

...unless you use a typedef.

typedef int * IntPtr;

void fn1( const IntPtr i );
void fn2( IntPtr const i );

One final note: Unless you are working in a low-level domain, most C++ code should never declare a pointer. Therefore, that aspect of this discussion is probably more relevant to C.

nobar
That's totally not true! There are plenty of uses for pointers. For example, a pointer to a choice of local variables.
rlbond
@rlbond: I'm not sure I understand your example, but I'm guessing that a reference would work for that.
nobar
@rlbond: You're right that pointers have many uses. It's just that C++ gives you better (safer) ways to do what pointers did in C. C++ is a multi-paradigm language, and using the low-level (pointer-based) paradigm is important for some purposes, but in most cases, you're probably better off trying to minimize the use of raw pointers in favor of higher-level abstractions.
nobar
A: 

I agree with both of you. You should put the const after the type. I also find looking at it an abomination that must be destroyed. But my recent foray into the wonders of const value parameters has made me understand why putting the const second makes sense.

int *
int const *
int * const
int const * const

Just looking at that has the hairs on my neck standing. I'm sure it would confuse my co-workers.

EDIT: I was just wondering about using this in classes:

class Foo {
    Bar* const bar;
    Foo(const Foo&) = delete; // would cause too many headaches
public:
    Foo() : bar(new Bar) {}
    ~Foo() { delete bar; }
};

bar in this example is functionally equivalent to Bar& but it is on the heap and can be deleted. For the lifetime of each Foo, there will be a single Bar associated with it.

jmucchiello
+2  A: 

If it were only variables and pointers to them that could be const or not, it would probably not matter that much. But consider:

class MyClass
{
    public:
        int foo() const;
};

No way that const could be written anywhere else but trailing the function it refers to.

The shorter a style guide, the more likely developers will follow it. And the shortest rule possible, and the only rule that will give you consistency, is:

The const keyword always trails whatever it is referring to.

So, I'd say 0:3 for your coworker here.

Regarding your "ultimate issue": For the sake of the style guide, it does not matter whether the guide "discourages" or "bans" the things it speaks out against. That is a social issue, a policy. The style guide itself should be as crisp and short as possible. Long style guides just get ignored by everybody (except management on the lookout for someone to blame), so just write "do" or "don't", and state what you do with violations of the guide elsewhere (e.g. in the company policy of how peer reviews are being done).

DevSolar