Solved How rigorous are you about using const?
-
@Chris-Kawa Look man, I've been coding since the days of Fortran-4 and have forgotten more languages than typical programmers even know exist. I was brought up in a generation where you turned 12 and you found a 22lr under the christmas tree, and your dad simply said, "don't hurt anyone". In short, we didn't have all these ridiculous, hard to swallow rules designed to "protect us from ourselves", and because management didn't trust us...As was said in "real programmers don't use Pascal" "real programmers don't like WYSIWYG. We want you asked for it, you got." And I'm always going to challenge those blanket statements about obscure studies and cases that "have proven time and time again" a particular point of view. More often than not they are simple dogma to support a persons particular religion. So yeah, maybe I can tune a compiler with flags to get behaviour that doesn't rub me raw...but...it sure as hades ain't gonna fly with the code nazis who are 1) half my age, 2) were poor programmers so they ended up being leads, 3) are on a quest to lower everyone to a least common denominator, and 4) are a big part of the mission to make "process" more important than "product"...becuase they don't really understand the product and feel empowered by introducing process instead.
Angry? Well, very jaded, to say the least...Until you've been a 50 yo programmer who had a 33yo lead tell you he was going to "teach you to program" because he didn't want to look at a piece of code and be able to tell who wrote it out of a team of five...well, our experiences are probably very different.
Anyway, I digres...forgive the rant.
-
@Kent-Dorfman said:
Anyway, I digres...forgive the rant.
No problem. I can see where you come from. The longer you're in the more stuff accumulates and it's good to let some of it out from time to time. We're here for (and with) you ;)
Until you've been a 50 yo programmer who had a 33yo lead tell you he was going to "teach you to program" because he didn't want to look at a piece of code and be able to tell who wrote it out of a team of five...well, our experiences are probably very different.
Not by much, but yeah and I'm sorry to hear that yours is like this. I can only again tell you it's not everywhere like that.
Where I'm at I get along with people both twice and half my age. Actually I'm often the guy that tries to make those two groups talk to each other, because, from what I've seen, that's when magic truly happens :) With the older gen we do have a relation where I can maybe hint them that they don't have to copy paste that function 30 times if they just use a simplest template and I get to see some cool low level tricks they developed over the years to pass along to the younger staff. It can be really synergetic if you let it. It's only "us vs them" if you all make it so. With the younglings it's similar. Sure, you can meet some arogant a-holes thinking they know everything because they followed a tutorial on youtube, but you either whack some sense into them or just part ways. They will learn eventually or they won't and go become a manager at another company ;) That's just how the industry rolls. You can get grumpy about the system or learn to live within it and shape it from the inside.
I mean look at it from the perspective of a fresh fish in the pond. Here you come, sure of yourself, full of enthusiasm and there along shows up this whiny grandpa that says everything you do is wrong and that's not how it was done in his days... It doesn't matter that you're right. You're not gonna have a very good working relation this way and you won't pass any of the knowledge you undoubtedly amassed over the years. To make someone learn you first need them to listen and for that to happen they must either like you, or at least tolerate you. The best way to make someone change their ways is to make them believe they came up with it themselves, not by hammering into them that their way is bad. Works wonders with some clueless management in my experience ;) I particularly like the trick of giving them two options, one of which is so bad they can't possibly choose it so you get your way and them being proud of themselves when it turns out ok. Win win :)
And I'm always going to challenge those blanket statements about obscure studies and cases that "have proven time and time again" a particular point of view.
Fair enough. That's something I really like in people and I do try to avoid empty words not backed up by some data. It's just not always feasible to tie in actual scientific articles and lengthy study summaries into ad hoc discussions like this. I'll try to be more rigorous about that though. Thanks for pointing that out.
In short, we didn't have all these ridiculous, hard to swallow rules designed to "protect us from ourselves", and because management didn't trust us
Yeah, sure, but I think you're projecting a bit too much. Not every language feature after early C is like that.
const
is very much not so and was introduced by the old timers like you actually to improve. It was widely adopted into other languages ever since because it's just a really useful feature, not because some knowitall said so.- are a big part of the mission to make "process" more important than "product"...becuase they don't really understand the product and feel empowered by introducing process instead.
Yeah, I share the sentiment. There are people like that, but what are you gonna do? There's almost 8b people on the planet. You're gonna meet some of those no matter what. I met a person somewhat like that once. First I tried to work with them, then work around them and when that didn't work I just changed jobs. Turns out best decision in my career ;)
-
Answering the original question, I am a little inconsistent in the use of
const
. At one point I tried to use it everywhere for local variables. (It never occured to me to use it on arguments as well, except for the obvious const ref, e.g.const std::string &str
). Currently, I am usingconst
a lot less because I am working on an older project where member functions are rarely const. I don't see much help in this case.In general, I would advocate the use of const. It should make your intent clearer. If done right, const-methods only should return const objects (copy, const-ref, or const pointer). This automatically means that you need to declare your local temporary variables const in many places. With modern C++ you could use
auto
instead. Though even then I preferconst auto
or evenconst auto &
instead of plainauto
. To be honest, I discourage the use ofauto
in these cases (going against the mantra of Herb Sutter et al.). Using the example of the OP:QWidget *widg = otherClass->someMethod(abc, def);
is IMHO a lot better than
auto widg = otherClass->someMethod(abc, def);
as the former states that we are expecting a
QWidget
. The strongest point about C++ is that it has static typing which helps to find a lot of errors at compile time. We need to give the compiler as much information as possible to help us catch these kind of errors. This means usingQWidget
instead ofauto
in the example and it means usingconst
everywhere if possible.The major point about using
const
everywhere is about future-proofing your software. There are many statements thatconst
means thread-safe, or at least should mean thread-safe. The standards committee is strongly pushing in this direction. If you are careful in the use and implementation of const in your classes, a consistent use of const sets you up for using multi-threading in your software in the future.Lastly, I want to talk about performance. I don't have any numbers, but it is more like my collected wisdom from many years of curiosity. It is my current understanding of this complex topic, but please do correct me if you know I am wrong. First of all, I think that compilers are very smart nowadays. In many cases I expect compilers to figure out if some local variable is changed during its lifetime. Especially for built-in types this would not really make a performance difference (at least when turning on at least some optimizations). Just maybe there are very few additional optimizations a compiler can do if you declare integer or floating point numbers as const, but I wouldn't hold my breath for it. For user defined types it is certainly a different story what the compiler is able to figure out on its own. Providing const members at all is certainly necessary, but I am not sure if compilers really do assume that const methods do not change the object and do optimizations accordingly. It certainly can make a difference when having overloaded const- and non-const-members. What comes to mind is
operator[](int)
andoperator[](int) const
ofstd::vector
and other vector classes, likeQVector
. For small types, likeint
anddouble
, the const version can return a copy of the value. I remember vagely that for some vector class the implementation of the non-const version is required to return a separate reference type to support all features. This means an actual separate object that behaves like the contained type of the vector, but actually is a wrapper class only referencing the actual object. For these special cases performance can be different. Nobody should remember these corner cases, but instead use const whenever possible. For me, writing scientific software, this is especially crucial for matrix classes where you might acces just a single row or column or even indexing a single element.Reading through previous answers, there are two things I never really thought about: 1. I never really thought about using const for arguments. 2. I have never really thought about their use with pointers. Going back to the example:
QWidget *widg = otherClass->someMethod(abc, def);
In general, I would introduce
const
like this:const QWidget *widg = otherClass->someMethod(abc, def);
Now, that I think about it I notice that this only makes only the
QWidget
object const (which helps to catch the most common errors associated with const). Especially in the context of the local temporary variable the pointer itself is also const in common use cases. This begs the question how to write it:const QWidget *const widg = otherClass->someMethod(abc, def);
or
QWidget const *const widg = otherClass->someMethod(abc, def);
Which variant do you prefer? (These two versions are really equivalent to the compiler.) If we were to agree on the rule "use const everywhere", should this include making the pointer const as well or would just
const QWidget *widg
be enough? -
@SimonSchroeder said:
In many cases I expect compilers to figure out if some local variable is changed during its lifetime.
I think it was at some cpp con few years back that one of the implementers of LLVM said blatantly that they just straight ignore const in most of the optimizer passes. That's mostly because
const_cast
exists and any optimizations they might think of have some corner case that generates hard to diagnose or debug casting problems so it's just not worth it. Also you can't assume anything about a variable that crosses object file boundaries, unless you use something like WPO, but I don't think anyone is really optimizing for const beyond maybe some basic stuff.What comes to mind is operator and operator const of std::vector and other vector classes, like QVector
I don't think it matters for std:: but with Qt containers const is important because of implicit sharing. non-const methods cause a detach that can be costly in many cases.
This begs the question how to write it:
IMO it's a pointless debate about east const vs west const. There are endless arguments that it should read right to left or like spoken word. Should programming languages read like books or shouldn't? Outside to inside or inside to outside? It should stay with type or with the indirection character. All of that just boils down to personal preference I think. I use west const just because that's how I learned it and most projects I worked in used it that way but I don't have any strong opinion either way. I don't care which is used, but the thing that actually bugs me is that there are two ways to use it. It's just unnecessary and I'd prefer much more to have only one valid syntax for it (whichever it is) because all that choice does is confuse the hell out of people, especially fresh C++ers.
-
That's one place where a simple new keyword could clarify a lot and make code more readable on first sight:
const_object
(orconst_pointee
or whatever).const_object QWidget *blah; // Object is const, pointer is not const QWidget *blah; // Pointer is const, object is not const const_object QWidget *blah; // Both are const. For clarity, const_pointer could be added, too
I don't think anybody cares for it enough to change suggest it. C++ was always proud of it's hard to read syntax ;-)
-
@sierdzio The committee is usually very reluctant to add new keywords, especially if they're just sugar and I must admit I agree with them on this one. I really don't want to write
constexpr const const_object Foo* const_pointer const
if I don't have to :P -
Hah, that's a strong argument indeed.
-
@Chris-Kawa said in How rigorous are you about using const?:
constexpr const const_object Foo* const_pointer const if I don't have to
you mean,
super_const
😎 -
@Chris-Kawa said in How rigorous are you about using const?:
It's just unnecessary and I'd prefer much more to have only one valid syntax for it (whichever it is) because all that choice does is confuse the hell out of people, especially fresh C++ers.
I guess that most people learned west syntax. The thing is that
const
always modifies what is immediately left of it. Obviously, this rule does not work for west const. So, basically this is the only exception to the rule. Which means it would make more sense to adopt east syntax as it is more consistent throughout. However, I expect a very strong resistance in the C++ community to ditch west const entirely (everybody learned it like that).const QWidget *blah;
is already defined to be a const object. This will never be redefined to mean a const pointer to a mutable object. And I also don't mind writing const pointer to mutable object like this:
QWidget *const blah;
However, I guess that people mostly will write only a single
const
. What would be helpful then is a small wrapper for a const pointer to a const object, e.g.:const_ptr<QWidget> blah;
This could belong to the Guidelines Support Library of the C++ Core Guidelines. I thought I once heard a suggestion like this, but couldn't find it again. I could be that it was related to pointers as members of a class: If accessing a member pointer (both non-const pointer and non-const object) from a const member function, constness only applies to the pointer but not the object. Maybe what I remember was related to this (but I can't still find it). Certainly, even if you apply
const
properly everywhere this is the place where it breaks. -
That thread did spiral somewhat. Bringing it back to the original question (as I'm late to the party):
@JonB, I personally useconst
only for members, references and globals/statics. I don't see no sense in doing it for a function argument (as it's already a copy) and I most certainly don't see any gain in doing it for locals*.* Exception is when I deal with Qt's iterators I force const iterators whenever I can to be absolutely sure I don't detach the container accidentaly.
-
@kshegunov said in How rigorous are you about using const?:
I don't see no sense in doing it for a function argument (as it's already a copy)
If passed by value. But the benefit of const for "by value" parameters is that you can't change them by mistake (if they should not be changed inside the function). Another benefit is that const clearly states that the function should not change the parameter.
Same goes for locals.Personally I always use const if something should not be changed.
-
@jsulm said in How rigorous are you about using const?:
If passed by value.
Yes, as I said:
... use const only for members, references and globals/statics.
But the benefit of const for "by value" parameters is that you can't change them by mistake (if they should not be changed inside the function).
I may throw by mistake too. Not all mistakes are preventable, and I really see no reason to sprinkle const liberally just for me. (the compiler doesn't care, nor should it, as @Chris-Kawa already mentioned)
Another benefit is that const clearly states that the function should not change the parameter.
Which as Chris already mentioned is none of the user of said function's business.
Same goes for locals.
So I prevent meself from changing something, so I don't accidentally change it, but then if I actually need to change it I unprevent myself. No thanks.
The big difference between a local (or a function argument) and a global (where it actually makes sense) is the scope of the state. A global is an application global state, while a function variable is self-contained in the function, so much so that it doesn't break reentrancy and thus doesn't introduce side effects on interruption. So for me usingconst
in that tiny ecosystem is like putting a protective band around sheets of paper, so you don't get a paper cut. Doesn't sound like a smart use of my time is all.Personally I always use const if something should not be changed.
We are going to disagree on the objective side of this argument, but you can do as you please, it's not wrong to do for certain.
-
@sierdzio said in How rigorous are you about using const?:
That's one place where a simple new keyword could clarify a lot and make code more readable on first sight: const_object (or const_pointee or whatever).
Sidetracking a bit - that wouldn't work, because you can have, albeit rare,
QWidget **
, thenconst
is supposed to modify which pointer exactly? Current semantics is fine I think. And to be honest I believe noobsters have much more problems with dangling pointers than accidentally modifying stuff, for whichconst
doesn't help at all. And I'm pretty sure of it as I was a noobster once too ... :) -
I am glad to have started such a big discussion :)
For my own part, I shall:
-
Obviously, for any global/member variables which are genuinely meant to be
const
I will put that in. That was never the question. -
When I choose to create a temporary pointer, I will (try to) make the effort to put in
const
(e.g.const QWidget *widg = something; widg->constMethod();
) where I only need to use the variable to call somethingconst
. Just as I would it it were a formal parameter to a method. -
But for non-pointer simple value types, whether as local variables or formal parameters, for right or for wrong I 'm not going to cover my code with
const
. It's just too much to type, and I'd rather saveconst
for where it actually matters.
Thanks to all. I'll close this in a couple of days, give y'all some more time to disagree with each other ;-)
-