Member variable decoration
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
canonical-development-guidelines |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
The style guides says:
Variable names are all lowercase, with underscores between words. Class member variables follow this convention. For
instance: my_exciting_
This was changed from the original text in the Google style guide:
Variable names are all lowercase, with underscores between words. Class member variables have trailing underscores. For
instance: my_exciting_
I take it that the intent is to *forbid* decoration of member variables rather than just making it optional.
However, there is no rationale to explain why not decorating the members is better.
Some thoughts on this:
By all means, if I have a class with only one or two members (such as pimpl which always only has a single data member), decorating the member name is unnecessary.
For classes with several member variables that do complex things, I don't think it's all that clear-cut.
Consider seeing "x = val;" somewhere in the body of a member function. What kind of thing could that "x" be that's assigned to here? I can think of the following (not sure whether that's a complete list).
- local variable
- parameter
- member variable
- member variable in a direct or indirect base class
- file static variable
- namespace variable in a direct or indirect enclosing namespace
- namespace variable in an anonymous namespace in the same source or header file
- extern variable
- global variable
Why is it desirable to force member variables to look exactly like every other variable? Has anyone ever noticed the similarity of member variables to global variables? While I'm inside the body of a method, I can just assign to member variables without having to declare them. They just "float around", much like globals do.
When I write code, I find it helpful to distinguish member and non-member variables. I find it also helpful when reading my code or someone else's code later. If I see "m_var" (or "var_"), I know without having to check anywhere at all that a member variable is being assigned. This reduces the amount of state I have to hold in my head, and saves me having to look for the definition of the variable in a header file. This is particularly true when I need to work with code written by someone else that I'm not familiar with.
Now, we may disagree on where the trade-off point should be between decorating and not decorating. But why should it be *forbidden* for me to this?
The member variable decorating convention has been with us for a good twenty years. It is recommended by the following style guidesj (and probably many others):
- Google
- Geosoft
- possibility.com
- ros.org
- GNU
- Microsoft
- C++ Coding Standards (by Sutter and Alexandrescu)
Just because something is old doesn't make it right. But I'm truly wondering whether disallowing the decoration is the right thing to do, especially when considering that most C++ programmers will be used to it.
There is also member variable initialization, for which the following has become very much idiomatic:
MyClass:
m_path(path),
m_size(size),
m_try_
If I can't use decorations, I have to artificially invent parameter or member variable names that differ, just to avoid the namespace collision. If nothing else, that's annoying.
I would much prefer for the style guide to at least permit the decoration. Whether in the form of "m_var" or "var_" is neither here nor there to me. (They both seem to be used with about the same frequency.)
Related branches
- Jussi Pakkanen (community): Approve
-
Diff: 31 lines (+16/-4)1 file modifiedc++/cppguide.xml (+16/-4)
Changed in canonical-client-development-guidelines: | |
status: | New → Fix Released |
The main point of decorating class variables is that "they can be easily separated from local variables". This description itself tells that what decoration is doing is treating a symptom, not the cause. If you can't easily tell the difference between local and class variables, the method is _badly designed_. To quote Clean Code:
Functions should do one thing. They should do it well. They should do it only.
And:
Functions need to be small.
They need to be even smaller.
They should probably be smaller than that.
In C it is hard to have small functions because of low level language primitives. In C++ you can have very readable and expressive code so that most functions should not exceed 15 lines or so. When your code is simple, the difference of variable type becomes obvious. That is what we should be focusing on: improving code quality rather than inventing better and better crutches.
> Why is it desirable to force member variables to look exactly like every other variable?
> Has anyone ever noticed the similarity of member variables to global variables?
If you have enough global variables to confuse them with local variables the problem is unambiguous: you have too many global variables and should get rid of them as soon as possible. Most applications should have zero. If you want to separate globals from instance variables then decorate the globals (maybe put them in a single global struct or something). That makes more sense because dealing with global variables is an exceptional case and should always be done with caution. It is better to emphasize the exceptional rather than the common.
> The member variable decorating convention has been with us for a good twenty years.
> It is recommended by the following style guidesj (and probably many others):
On the other hand the style guide of Java, which was designed after C++ by people who used C++ for the implementation and it specifically forbids decorations.
> There is also member variable initialization, for which the following has become very much idiomatic: :MyClass( const string& path, int size, bool try_again) : try_again)
>
> MyClass:
> m_path(path),
> m_size(size),
> m_try_again(
>
> If I can't use decorations, I have to artificially invent parameter or member variable names that differ,
> just to avoid the namespace collision. If nothing else, that's annoying.
This is not necessary. You can use the same name, like this:
class Foo {
private:
int x;
public:
Foo(int x) : x(x) {}
};
Compiles, works, does exactly what you'd expect. If you absolutely, positively, have to have decoration, put it in the constructor argument because then it is isolated to one line and does not leak to other parts of the code.
Some random thoughts:
If you must have decoration, use the suffix rather than a prefix. The reason for this is that the prefix makes code completion more tedious. (i.e. to complete variable myVarName_ you can just type myv + ctrl+space, as opposed to m_myv + ctrl+space)
If you use a pimpl, all variables should be put in it and the variable name p should not be decorated. The reason being that p works as a decoration of sorts and adding more is just noise. Cont...