When writing some functions, I found a const keyword in parameters like this:
void MyClass::myFunction(const MyObject& obj,const string& s1,const string& s2,const string& s3){
}
often causes splitting a line into 2 lines in IDE or vim, so I want to remove all const keywords in parameters:
void MyClass::myFunction(MyObject& obj,string& s1,string& s2,string& s3){
}
is that a valid reason to not using const? Is it maintainable to keep the parameter objects unchanged manually?
6 Answers 6
Readability is a valid reason to learn to use whitespace:
void MyClass::myFunction(
const MyObject& obj,
const string& s1,
const string& s2,
const string& s3
) {
return;
}
Located over there the parameters won't get confused with the body of the function. By locating them on a different line you won't have to reposition them when you change the name of myFunction
to something more descriptive. Not changing the parameters position when they haven't changed is something source control diff tool users will appreciate.
const
means something. Don't throw it out just because you're out of space and ideas. Readability is king but breaking things in it's name is just giving up.
-
6"you won't have to reposition them when you change the name of myFunction" -- although in this case it looks as if they have been positioned to approximately line up with the opening
(
, and if that's the case then you might have to reposition them if the length of the class+function name changes by more than about 4 characters. So if you want not to have to do that, add a fixed number of levels of indentation, not a number that depends on the length of the function name. I would recommend 1 level, this answer uses 6, but any fixed number achieves the stated goal :-)Steve Jessop– Steve Jessop2016年09月22日 10:32:55 +00:00Commented Sep 22, 2016 at 10:32 -
6@CandiedOrange I'm surprised you didn't use "form 6" in this answer ... it's clearly less ugly!svidgen– svidgen2016年09月22日 15:05:30 +00:00Commented Sep 22, 2016 at 15:05
-
6Form 6 for the win. One tabspace for one level of indentation. Simple and effective. Problem solved :)Lightness Races in Orbit– Lightness Races in Orbit2016年09月22日 15:47:27 +00:00Commented Sep 22, 2016 at 15:47
-
2Ok ok form 6 it is. This is the variant that JeffGrigg mentioned on c2.candied_orange– candied_orange2016年09月22日 16:55:24 +00:00Commented Sep 22, 2016 at 16:55
-
5@random832 I think we're firmly in bike shed territory now. Here's the proper way to resolve that: search your code base for examples, consult your shops style guide, ask the developers in your shop, and if none of that yields an authoritative answer use this. Resolve disputes that could go either way with a quarter. Once the quarter has spoken be consistent!candied_orange– candied_orange2016年09月22日 19:50:06 +00:00Commented Sep 22, 2016 at 19:50
Actually, the readability issue definitely goes the other direction. First, you can trivially solve your run-on line by the use of whitespace. But removing const
doesn't just make the line shorter, it completely changes the meaning of the program.
Herb Sutter refers to the const
in reference to const
as the most important const
because a reference to const
can bind to a temporary and extend its lifetime. An lvalue reference to non-const
cannot, you need a separate variable.
void foo_const(std::string const& );
void foo_nc(std::string& );
std::string some_getter();
foo_const(some_getter()); // OK
foo_const("Hello there"); // OK
foo_nc(some_getter()); // error
foo_nc("Nope"); // error
std::string x = some_getter(); // have to do this
foo_nc(x); // ok
std::string msg = "Really??"; // and this
foo_nc(msg); // ok
What this means for usability is that you'll have to introduce all these temporary variables just to be able to call your function. That's not great for readability, since these variables are meaningless and exist only because your signature is wrong.
-
7Your second paragraph gives me headaches trying to figure out if
const
is refering toconst
or to the otherconst
and whatconst
is indeed the most importantconst
Mindwin Remember Monica– Mindwin Remember Monica2016年09月23日 17:51:14 +00:00Commented Sep 23, 2016 at 17:51 -
3@Mindwin I think the irony is that my second paragraph is clear and unambiguous, and I have no idea what you're talking about.Barry– Barry2016年09月23日 18:45:15 +00:00Commented Sep 23, 2016 at 18:45
-
2@Barry It is certainly unambiguous, but it took me a few reads of that paragraph to try to figure out what it meant. I think some of the trouble is that it can be parsed "Herb Sutter refers to the const (in reference to const) as the most important const..." or "Herb Sutter refers to const in (reference to const) as the most important const..." I believe the latter is the only valid grouping of the words, but it takes a bit to process it. Maybe there's a way to use quotation marks to remove the ambiguity?Cort Ammon– Cort Ammon2016年09月23日 18:50:22 +00:00Commented Sep 23, 2016 at 18:50
-
1I think some hyphenated compounds would clear this up.shawnt00– shawnt002016年09月23日 20:57:09 +00:00Commented Sep 23, 2016 at 20:57
-
2or specifically use
const&
rather than reference toconst
as a noun(-phrase) thereCaleth– Caleth2016年10月06日 08:26:30 +00:00Commented Oct 6, 2016 at 8:26
Simple answer is "no".
The long answer is that the const
keyword is part of the contract the function offers; it tells you that the argument will not be modified. The moment you remove the const
that guarantee goes out of the window.
Remember that you can't reasonably maintain the constness (or any other property) of something using documentation, conventions, or guidelines - if the constness is not enforced by the compiler, someone will think that they can make their work easier if they fiddle with the parameter "just a little bit".
Consider:
// parameter "foo" is not modified
void fna(Foo& foo);
void fnb(const Foo& foo);
Apart from the fact that the latter version is more concise, it also provides stronger contract, and lets the compiler help you maintain your intentions.
The former does nothing to prevent the fna(Foo&)
function from modifying the parameter you pass to it.
As in @CandiedOrange answer, you can use whitespace to lay out the code and enhance readability.
Removing the const
keyword removes readability because const
communicates information to the reader and the compiler.
Reducing the horizontal length of code is good (nobody likes scrolling sideways) but there's more to const
than text. You could rewrite it:
typedef string str;
typedef MyObject MObj;
void MyClass::myFunction(const MObj& o,const str& s1,const str& s2,const str& s3)
Which doesn't change the contract but fulfils the need to reduce line length. Truly I would consider the above snippet to be less readable and would opt for using more whitespace as already mentioned in CandiedOrange's answer.
const
is a functionality of the code itself. You wouldn't make the function a non-member to remove the MyClass::
section of the declaration, so don't remove the const
-
4I agree that the snippet you provide is less readable. It forces a reader to go find out what
MObj
andstr
are, and certainly raises eyebrows. It's especially weird for types whose names you already have control over: E.g. Why didn't you just nameMyObject
asMObj
to begin with?Jason C– Jason C2016年09月22日 20:52:16 +00:00Commented Sep 22, 2016 at 20:52
Is readability a valid reason to not use const in parameters?
No. Omitting const
can change functionality, lose protections const
provides and can potentially create less efficient code.
Is it maintainable to keep the parameter objects unchanged manually?
Rather than spend time manually formating code
void MyClass::myFunction(const MyObject& obj,const string& s1,const string& s2,const string& s3){
//
}
Use auto formatting tools. Write the function per its functional requirements and let auto-formatting handle the presentation. Manually adjusting formatting is not as efficient as using auto formatting and using the saved time to improve other aspects of code.
void MyClass::myFunction(const MyObject& obj, const string& s1, const string& s2,
const string& s3) {
//
}
As long as possible it is better to keep const visible. It improves code maintenance a lot (no guesswork to see if this method changes my arguments).
If I see lot of arguments in a method, it forces me to consider creation of project based jaron (Matrix, Employee, Rectangle, Account) that would be much shorter, easier to understand (eliminates long list of arguments to methods).
-
Agreed. I was hesitant to point it out. Thus, "extreme case".blackpen– blackpen2016年09月22日 21:04:22 +00:00Commented Sep 22, 2016 at 21:04
-
@cmaster That said, sometimes in certain contexts, with certain programmers, it could stay readable. For example, in the very specific case of a program waist-deep in Windows API calls, with a reader who is used to that environment, stuff like e.g.
typedef Point * LPPOINT
andtypedef const Point * LPCPOINT
, while super obnoxious, still carries an implicit meaning, because it's consistent with immediate expectations in context. But never in the general case; it's just a weird exception I can think of.Jason C– Jason C2016年09月22日 21:25:04 +00:00Commented Sep 22, 2016 at 21:25 -
1Yes, when I saw the question, "const unsigned long long int" came to my mind, but, it is not a good candidate to derive benefit from being either "const" or "reference". The typedef solves the general problem of shortening names; but it doesn't feel like good design to hide the very purpose of language constructs (like "const") behind it.blackpen– blackpen2016年09月22日 21:37:37 +00:00Commented Sep 22, 2016 at 21:37
const
you have a strong hint that you don't need to bother how it might be changed in the function.