Why is const-correctness specific to C++? - c++

Disclaimer: I am aware that there are two questions about the usefulness of const-correctness, however, none discussed how const-correctness is necessary in C++ as opposed to other programming languages. Also, I am not satisfied with the answers provided to these questions.
I've used a few programming languages now, and one thing that bugs me in C++ is the notion of const-correctness. There is no such notion in Java, C#, Python, Ruby, Visual Basic, etc., this seems to be very specific to C++.
Before you refer me to the C++ FAQ Lite, I've read it, and it doesn't convince me. Perfectly valid, reliable programs are written in Python all the time, and there is no const keyword or equivalent. In Java and C#, objects can be declared final (or const), but there are no const member functions or const function parameters. If a function doesn't need to modify an object, it can take an interface that only provides read access to the object. That technique can equally be used in C++. On the two real-world C++ systems I've worked on, there was very little use of const anywhere, and everything worked fine. So I'm far from sold on the usefulness of letting const contaminate a codebase.
I am wondering what is it in C++ that makes const necessary, as opposed to other programming languages.
So far, I've seen only one case where const must be used:
#include <iostream>
struct Vector2 {
int X;
int Y;
};
void display(/* const */ Vector2& vect) {
std::cout << vect.X << " " << vect.Y << std::endl;
}
int main() {
display(Vector2());
}
Compiling this with const commented out is accepted by Visual Studio, but with warning C4239, non-standard extension used. So, if you want the syntactic brevity of passing in temporaries, avoiding copies, and staying standard-compliant, you have to pass by const reference, no way around it. Still, this is more like a quirk than a fundamental reason.
Otherwise, there really is no situation where const has to be used, except when interfacing with other code that uses const. Const seems to me little else than a self-righteous plague that spreads to everything it touches :
The reason that const works in C++ is
because you can cast it away. If you
couldn't cast it away, then your world
would suck. If you declare a method
that takes a const Bla, you could pass
it a non-const Bla. But if it's the
other way around you can't. If you
declare a method that takes a
non-const Bla, you can't pass it a
const Bla. So now you're stuck. So you
gradually need a const version of
everything that isn't const, and you
end up with a shadow world. In C++ you
get away with it, because as with
anything in C++ it is purely optional
whether you want this check or not.
You can just whack the constness away
if you don't like it.
Anders Hejlsberg (C# architect), CLR Design Choices

Const correctness provides two notable advantages to C++ that I can think of, one of which makes it rather unique.
It allows pervasive notions of mutable/immutable data without requiring a bunch of interfaces. Individual methods can be annotated as to whether or not they can be run on const objects, and the compiler enforces this. Yes, it can be a hassle sometimes, but if you use it consistently and don't use const_cast you have compiler-checked safety with regards to mutable vs. immutable data.
If an object or data item is const, the compiler is free to place it in read-only memory. This can particularly matter in embedded systems. C++ supports this; few other languages do. This also means that, in the general case, you cannot safely cast const away, although in practice you can do so in most environments.
C++ isn't the only language with const correctness or something like it. OCaml and Standard ML have a similar concept with different terminology — almost all data is immutable (const), and when you want something to be mutable you use a different type (a ref type) to accomplish that. So it's just unique to C++ within its neighboring languages.
Finally, coming the other direction: there have been times I have wanted const in Java. final sometimes doesn't go far enough as far as creating plainly immutable data (especially immutable views of mutable data), and don't want to create interfaces. Look at the Unmodifiable collection support in the Java API and the fact that it only checks at run time whether modification is allowed for an example of why const is useful (or at least the interface structure should be deepend to have List and MutableList) — there is no reason that attempting to mutate an immutable structure can't be a compile-type error.

I don't think anybody claims const-correctness is "necessary". But again, classes are not really necessary either, are they? The same goes for namespaces, exceptions,... you get the picture.
Const-correctness helps catch errors at compile time, and that's why it is useful.

const is a way for you to express something. It would be useful in any language, if you thought it was important to express it. They don't have the feature, because the language designers didn't find them useful. If the feature was there, it would be about as useful, I think.
I kind of think of it like throw specifications in Java. If you like them, you would probably like them in other languages. But the designers of the other languages didn't think it was that important.

Well, it will have taken me 6 years to really understand, but now I can finally answer my own question.
The reason C++ has "const-correctness" and that Java, C#, etc. don't, is that C++ only supports value types, and these other languages only support or at least default to reference types.
Let's see how C#, a language that defaults to reference types, deals with immutability when value types are involved. Let's say you have a mutable value type, and another type that has a readonly field of that type:
struct Vector {
public int X { get; private set; }
public int Y { get; private set; }
public void Add(int x, int y) {
X += x;
Y += y;
}
}
class Foo {
readonly Vector _v;
public void Add(int x, int y) => _v.Add(x, y);
public override string ToString() => $"{_v.X} {_v.Y}";
}
void Main()
{
var f = new Foo();
f.Add(3, 4);
Console.WriteLine(f);
}
What should this code do?
fail to compile
print "3, 4"
print "0, 0"
The answer is #3. C# tries to honor your "readonly" keyword by invoking the method Add on a throw-away copy of the object. That's weird, yes, but what other options does it have? If it invokes the method on the original Vector, the object will change, violating the "readonly"-ness of the field. If it fails to compile, then readonly value type members are pretty useless, because you can't invoke any methods on them, out of fear they might change the object.
If only we could label which methods are safe to call on readonly instances... Wait, that's exactly what const methods are in C++!
C# doesn't bother with const methods because we don't use value types that much in C#; we just avoid mutable value types (and declare them "evil", see 1, 2).
Also, reference types don't suffer from this problem, because when you mark a reference type variable as readonly, what's readonly is the reference, not the object itself. That's very easy for the compiler to enforce, it can mark any assignment as a compilation error except at initialization. If all you use is reference types and all your fields and variables are readonly, you get immutability everywhere at little syntactic cost. F# works entirely like this. Java avoids the issue by just not supporting user-defined value types.
C++ doesn't have the concept of "reference types", only "value types" (in C#-lingo); some of these value types can be pointers or references, but like value types in C#, none of them own their storage. If C++ treated "const" on its types the way C# treats "readonly" on value types, it would be very confusing as the example above demonstrates, nevermind the nasty interaction with copy constructors.
So C++ doesn't create a throw-away copy, because that would create endless pain. It doesn't forbid you to call any methods on members either, because, well, the language wouldn't be very useful then. But it still wants to have some notion of "readonly" or "const-ness".
C++ attempts to find a middle way by making you label which methods are safe to call on const members, and then it trusts you to have been faithful and accurate in your labeling and calls methods on the original objects directly. This is not perfect - it's verbose, and you're allowed to violate const-ness as much as you please - but it's arguably better than all the other options.

You're right, const-correctness isn't necessary. You can certainly write all your code without the const keyword and get things to work, just as you do in Java and Python.
But if you do that, you'll no longer get the compiler's help in checking for const violations. Errors that the compiler would have told you about at compile-time will now be found only at run-time, if at all, and therefore will take you longer to diagnose and fix.
Therefore, trying to subvert or avoid the const-correctness feature is just making things harder for yourself in the long run.

Programming is writing in a language that will be ultimately processed by the computer, but that is both a way of communicating with the computer and other programmers in the same project. When you use a language, you are restricted to the concepts that can be expressed in it, and const is just one more concept you can use to describe your problem, and your solution.
Constantness enables you to express clearly from the design board to the code one concept that other languages lack. As you come from a language that does not have it, you may seem puzzled by a concept you have never used --if you never used it before, how important can it be?
Language and thought are tightly coupled. You can only express your thoughts in the language you speak, but the language also changes the way you think. The fact that you did not have the const keyword in the languages you worked with implies that you have already found other solutions to the same problems, and those solutions are what seems natural to you.
In the question you argued that you can provide a non mutating interface that can be used by functions that do not need to change the contents of the objects. If you think about it for a second, this same sentence is telling you why const is a concept you want to work with.
Having to define a non-mutating interface and implement it in your class is a work around the fact that you cannot express that concept in your language.
Constantness allows you to express those concepts in a language that the compiler (and other programers) can understand. You are establishing a compromise on what you will do with the parameters you receive, the references you store, or defining limits on what the users of your class are allowed to do with the references you provide. Pretty much each non-trivial class can have a state represented by attributes, and in many cases there are invariants that must be kept. The language lets you define functions that offer access to some internal data while at the same time limits the access to a read-only view that guarantees no external code will break your invariants.
This is the concept I miss more when moving to other languages. Consider an scenario where you have a class C that has among others an attribute a of type A that must be visible to external code (users of your class must be able to query for some information on a). If the type of A has any mutating operation, then to keep user code from changing your internal state, you must create a copy of a and return it. The programmer of the class must be aware that a copy must be performed and must perform the (possibly expensive) copy. On the other hand, if you could express constantness in the language, you could just return a constant reference to the object (actually a reference to a constant view of the object) and just return the internal element. This will allow the user code to call any method of the object that is checked as non-mutating, thus preserving your class invariants.
The problem/advantage, all depends on the point of view, of constantness is that it is viral. When you offer a constant reference to an object, only those methods flagged as non-mutating can be called, and you must tell the compiler which of the methods have this property. When you declare a method constant, you are telling the compiler that user code that calls that method will keep the object state. When you define (implement) a method that has a constant signature, the compiler will remind you of your promise and actually require that you do not internally modify the data.
The language enables you to tell the compiler properties of your methods that you cannot express any other way, and at the same time, the compiler will tell you when you are not complying with your design and try to modify the data.
In this context, const_cast<> should never be used, as the results can take you into the realm of undefined behavior (both from a language point of view: the object could be in read-only memory, and from a program point of view: you might be breaking invariants in other classes). But that, of course, you already know if you read the C++FAQ lite.
As a side note, the final keyword in Java has really nothing to do with the const keyword in C++ when you are dealing with references (in C++ references or pointers). The final keyword modifies the local variable to which it refers, whether a basic type or a reference, but is not a modifier of the referred object. That is, you can call mutating methods through a final reference and thus provide changes in the state of the object referred. In C++, references are always constant (you can only bind them to an object/variable during construction) and the const keyword modifies how the user code can deal with the referred object. (In case of pointers, you can use the const keyword both for the datum and the pointer: X const * const declares a constant pointer to a constant X)

If you are writing programs for embedded devices with data in FLASH or ROM you can't live without const-correctness. It gives you the power to control the correct handling of data in different types of memory.

You want to use const in methods as well in order to take advantage of return value optimization. See Scott Meyers More Effective C++ item 20.

This talk and video from Herb Sutter explains the new connotations of const with regards to thread-safety.
Constness might not have been something you had to worry about too much before but with C++11 if you want to write thread-safe code you need to understand the significance of const and mutable

In C, Java and C# you can tell by looking at the call site if a passed object can be modified by a function:
in Java you know it definitely can be.
in C you know it only can be if there is a '&', or equivalent.
in c# you need to say 'ref' at the call site too.
In C++ in general you can't tell this, as a non-const reference call looks identical to pass-by-value. Having const references allows you to set up and enforce the C convention.
This can make a fairly major difference in readability of any code that calls functions. Which is probably enough to justify a language feature.

Anders Hejlsberg (C# architect): ... If you declare a method that takes a non-const Bla, you can't pass it a const Bla. So now you're stuck. So you gradually need a const version of everything that isn't const, and you end up with a shadow world.
So again: if you started to use "const" for some methods you usually forced to use this in most of your code. But the time spent for maintaining (typing, recompiling when some const is missing, etc.) of const-correctness in code seems greater than for fixing of possible (very rare) problems caused by not using of const-correctness at all. Thus lack of const-correctness support in modern languages (like Java, C#, Go, etc.) might result in slightly reduced development time for the same code quality.
An enhancement request ticket for implementing const correctness existed in the Java Community Process since 1999, but was closed in 2005 due to above mentioned "const pollution" and also compatibility reasons: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070
Although C# language has no const correctness construct but similar functionality possibly will appear soon in "Microsoft Code Contracts" (library + static analysis tools) for .NET Framework by using [Pure] and [Immutable] attributes: Pure functions in C#

Actually, it's not... not entirely, anyway.
In other languages, especially functional or hybrid languages, like Haskell, D, Rust, and Scala, you have the concept of mutability: variables can be mutable, or immutable, and are usually immutable by default.
This lets you (and your compiler/interpreter) reason better about functions: if you know that a function only takes immutable arguments, then you know that function isn't the one that's mutating your variable and causing a bug.
C and C++ do something similar using const, except that it's a much less firm guarantee: the immutability isn't enforced; a function further down the call stack could cast away the constness, and mutate your data, but that would be a deliberate violation of the API contract. So the intention or best practice is for it to work quite like immutability in other languages.
All that said, C++ 11 now has an actual mutable keyword, alongside the more limited const keyword.

The const keyword in C++ (as applied to parameters and type declarations) is an attempt to keep programmers from shooting off their big toe and taking out their whole leg in the process.
The basic idea is to label something as "cannot be modified". A const type can't be modified (by default). A const pointer can't point to a new location in memory. Simple, right?
Well, that's where const correctness comes in. Here are some of the possible combinations you can find yourself in when you use const:
A const variable
Implies that the data labeled by the variable name cannot be modified.
A pointer to a const variable
Implies that the pointer can be modified, but the data itself cannot.
A const pointer to a variable
Implies that the pointer cannot be modified (to point to a new memory location), but that the data to which the pointer points can be modified.
A const pointer to a const variable
Implies that neither the pointer nor the data to which it points can be modified.
Do you see how some things can be goofy there? That's why when you use const, it's important to be correct in which const you are labeling.
The point is that this is just a compile-time hack. The labeling just tells the compiler how to interpret instructions. If you cast away from const, you can do whatever you want. But you'll still have to call methods that have const requirements with types that are cast appropriately.

For example you have a funcion:
void const_print(const char* str)
{
cout << str << endl;
}
Another method
void print(char* str)
{
cout << str << endl;
}
In main:
int main(int argc, char **argv)
{
const_print("Hello");
print("Hello"); // syntax error
}
This because "hello" is a const char pointer, the (C-style) string is put in read only memory.
But it's useful overall when the programmer knows that the value will not be changed.So to get a compiler error instead of a segmentation fault.
Like in non-wanted assignments:
const int a;
int b;
if(a=b) {;} //for mistake
Since the left operand is a const int.

Related

Why is C++'s void type only half-heartedly a unit type?

C++'s void type is not uninhabited. The problem is that while it has precisely one inhabitant, very much like the Unit type (a.k.a. ()) in ML-like languages, that inhabitant cannot be named or passed around as an ordinary value. For example, the following code fails to compile:
void foo(void a) { return; }
void bar() { foo(foo()); }
whereas equivalent (say) Rust code would compile just fine:
fn foo(a : ()) { return; }
fn bar() { foo(foo(())); }
In effect, void is like a unit type, but only half-heartedly so. Why is this the case?
Does the C++ standard explicitly state that one cannot create values of type void? If yes, what is the rationale behind this decision? If not, why does the code above not compile?
If it is some backwards-compatibility related reason, please give a code example.
To be clear, I'm not looking for work-arounds to the problem (e.g. using an empty struct/class). I want to know the historical reason(s) behind the status quo.
EDIT: I've changed the syntax in the code examples slightly to make it clear that I'm not trying to hijack existing syntax like void foo(void) (consequently, some comments may be out of date). The primary motivation behind the question is "why is the type system not like X" and not "why does this bit of syntax not behave as I'd like it to". Please keep this point in mind if you're writing an answer talking about breaking backwards compatibility.
"Does the C++ standard explicitly state that one cannot create values of type void?"
Yes. It states that void is an incomplete type and cannot be completed. You can't create objects or values with an incomplete type.
This is an old rule; as the comments note it's inherited from C. There are minor extensions in C++ to simplify the writing of generic code, e.g. void f(); void g() { return f(); } is legal.
There seems to be little gain in changing the status quo. C++ is not an academic language. Purity is not a goal. Writing useful program is, but how does such a proposal help with that? To quote Raymond Chen, every proposal starts at -100 and has to justify its addition; you don't justify the lack of features.
That is really an historical question. Old (pre-C) language used to differentiate functions which returned values, from subroutines which did not (ooh, the good old taste of Fortran IV and Basic...). AFAIK, early C only allowed functions, simply functions were by default returning int and it was legal to have no return statement (mean return an unspecified value) and legal to ignore any return value - so that the programmer can write coherent code... In those early days, C was used more or less as a powerful macro assembler, and anything was allowed provided the compiler can translate it into machine instructions (no strict aliasing rule for example...). As the memory unit was char, no need for void * pointer, char * was enough.
Then people felt the need to make clear that a buffer was expected to contain anything and not a character string, and that some functions will never return a value. And void came to feel the gap.
The drawback, is that when you declare a void function, you declare what was called a subroutine, that is something that can never be used as a value, in particular never be used as a function parameter. So void is not only a special type that can never be instantiated, it really declare that the result cannot be a member of an expression.
And because of language inheritance, and because the C standard library is still a subset of the C++ standard one, C++ still processes void the way ANSI C did.
Other languages can use different conventions. In Python for example a function will always return something, simply it returns the special None value if no return statement is encountered. And rust seem to have still another convention.

Const usage - What should be changed here to fix the issue?

I was reading Effective C++ book and it was talking about const correctness. The following code block was given:
class CTextBlock {
public:
...
char& operator[](std::size_t position) const // inappropriate (but bitwise
{ return pText[position]; } // const) declaration of
// operator[]
private:
char *pText;
};
The book was describing the potential issue with the above usage.
const CTextBlock cctb("Hello"); // declare constant object
char *pc = &cctb[0]; // call the const operator[] to get a
// pointer to cctb’s data
*pc = ’J’; // cctb now has the value “Jello”
What should be changed so that the assignment used in the last line is forbidden? The book didn't give a solution to the problem.
Thank you in advance for your help!
This is a result of how the different parts of the code work. Const is supposed to provide guidance on the usage of objects and prevent programming mistakes. By using it you are telling other programmers that this value should not be changed. There isn't actually a way to ensure that the data isn't changed. this is because in c++ there are a number of ways of accessing the underlying memory and changing it. In the example you have given this is through the use of pointers.
Why is this you might ask. A great answer can be found at: http://www.cprogramming.com/tutorial/const_correctness.html
The relevant section reads as follows:
First, why would you ever want to have the ability to change data in a class that's declared const? This gets at the heart of what constness means, and there are two ways of thinking about it. One idea is that of "bitwise constness", which basically means that a const class should have exactly the same representation in memory at all times. Unfortunately (or fortunately), this is not the paradigm used by the C++ standard; instead, C++ uses "conceptual constness". Conceptual constness refers to the idea that the output of the const class should always be the same. This means that the underlying data might change as long as the fundamental behavior remains the same. (In essence, the "concept" is constant, but the representation may vary.)
There are other ways to ensure that particular values remain constant ect that are harder to change or cannot be changed at runtime it that is your goal. You can also look at using #define or enum depending on what you are trying to achieve. I would recommend that before using any of them you research the differences as whilst they all perform similar functions the edge cases can have very different results and each on has different limitations. It is also worth noting that some developers have very strong opinions on which of these options should be used and when. For example is espoused that you should favour enum over #define for aa number of reasons as seen here: http://blogs.msdn.com/b/doronh/archive/2006/03/27/562502.aspx
A good description of the difference between enum and const can be found here: http://www.codeproject.com/Articles/4354/Enum-vs-Const
It is also worth noting that the way const works in c versus c++ is different so ensure when you are reading about how to use const and when that you are reading about its application in the correct language.
The accessor should return a const char & to restrict write-access to the return value.
const char& operator[](std::size_t position) const
would prevent that, except if the user of the code used const_cast to remove the const.
Adding const means that the data that the reference refers to can't be changed

Should we use constexpr everywhere we can?

We obviously can't make everything constexpr. And if we don't make anything constexpr, well, there won't be any big problems. Lots of code have been written without it so far.
But is it a good idea to slap constexpr in anything that can possibly have it? Is there any potential problem with this?
It won't bother the compiler. The compiler will (or should anyway) give you a diagnostic when/if you use it on code that doesn't fit the requirements of a constexpr.
At the same time, I'd be a bit hesitant to just slap it on there because you could. Even though it doesn't/won't bother the compiler, your primary audience is other people reading the code. At least IMO, you should use constexpr to convey a fairly specific meaning to them, and just slapping it on other expressions because you can will be misleading. I think it would be fair for a reader to wonder what was going on with a function that's marked as a constexpr, but only used as a normal run-time function.
At the same time, if you have a function that you honestly expect to use at compile time, and you just haven't used it that way yet, marking it as constexpr might make considerably more sense.
Why I don't bother to try and put constexpr at every opportunity in list form, and in no particular order:
I don't write one-liner functions that often
when I write a one-liner it usually delegates to a non-constexpr function (e.g. std::get has come up several times recently)
the types they operate on aren't always literal types; yes, references are literal types, but if the referred type is not literal itself I can't really have any instance at compile-time anyway
the type they return aren't always literal
they simply are not all useful or even meaningful at compile-time in terms of their semantics
I like separating implementation from declaration
Constexpr functions have so many restrictions that they are a niche for special use only. Not an optimization, or a desirable super-set of functions in general. When I do write one, it's often because a metafunction or a regular function alone wouldn't have cut it and I have a special mindset for it. Constexpr functions don't taste like other functions.
I don't have a particular opinion or advice on constexpr constructors because I'm not sure I can fully wrap my mind around them and user-defined literals aren't yet available.
I tend to agree with Scott Meyers on this (as for most things): "Use constexpr whenever possible" (from Item 15 of Effective Modern C++), particularly if you are providing an API for others to use. It can be really disappointing when you wish to perform a compile-time initialization using a function, but can't because the library did not declare it constexpr. Furthermore, all classes and functions are part of an API, whether used by the world or just your team. So use it whenever you can, to widen its scope of usage.
// Free cup of coffee to the API author, for using constexpr
// on Rect3 ctor, Point3 ctor, and Point3::operator*
constexpr Rect3 IdealSensorBounds = Rect3(Point3::Zero, MaxSensorRange * 0.8);
That said, constexpr is part of the interface, so if the interface does not naturally fit something that can be constexpr, don't commit to it, lest you have to break the API later. That is, don't commit constexpr to the interface just because the current, only implementation can handle it.
Yes. I believe putting such constness is always a good practice wherever you can. For example in your class if a given method is not modifying any member then you always tend to put a const keyword in the end.
Apart from the language aspect, mentioning constness is also a good indication to the future programmer / reviewer that the expression is having const-ness within that region. It relates to good coding practice and adds to readability also. e.g. (from #Luc)
constexpr int& f(int& i) { return get(i); }
Now putting constexpr suggests that get() must also be a constexpr.
I don't see any problem or implication due constexpr.
Edit: There is an added advantage of constexpr is that you can use them as template argument in some situations.

Argument order for mixed const and non-const pass-by-reference

In keeping with the practice of using non-member functions where possible to improve encapsulation, I've written a number of classes that have declarations which look something like:
void auxiliaryFunction(
const Class& c,
std::vector< double >& out);
Its purpose is to do something with c's public member functions and fill a vector with the output.
You might note that its argument order resembles that of a python member function, def auxiliaryFunction(self, out).
However, there are other reasonable ways of choosing the argument order: one would be to say that this function resembles an assignment operation, out = auxiliaryFunction(c). This idiom is used in, for example,
char* strcpy ( char* destination, const char* source );
What if I have a different function that does not resemble a non-essential member function, i.e. one that initializes a new object I've created:
void initializeMyObject(
const double a,
const std::vector<double>& b,
MyObject& out);
So, for consistency's sake, should I use the same ordering (mutable variable last) as I did in auxiliaryFunction?
In general, is it better to choose (non-const , const) over (const, non-const), or only in certain situations? Are there any reasons for picking one, or should I just choose one and stick with it?
(Incidentally, I'm aware of Google style guide's suggestion of using pointers instead of non-const references, but that is tangential to my question.)
The STL algorithms places output (non-const) values last. There you have a precedent for C++ that everyone should be aware of.
I also tend to order arguments from important, to less important. (i.e. size of box goes before box-margin tweak value.)
(Note though: Whatever you do, be consistent! That's infinitely more important than choosing this or that way...)
Few points that may be of help:
Yes, I like the idea of following the standard library's argument ordering convention as much as possible. Principle of least surprises. So, good to go. However, remember that the C standard library itself is not very well crafted, particularly if you look at the file handling API. So beware -- learn from these mistakes.
const with basic arithmetic types are rarely used, it'd be more of a surprise if you do.
The STL, even with its deficiencies provide, IMO, a better example.
Finally, note that C++ has another advantage called Return Value Optimization which is turned on in most modern compilers by default. I'd use that and rewrite your initializeMyObject or even better, use a class and constructors.
Pass by const-reference than by value -- save a lot of copying overhead (both time and memory penalties)
So, your function signature should be more like this:
MyObject initializeMyObject(
double a,
const std::vector<double>& b,
);
(And I maybe tempted to hide the std::vector<double> by a typedef if possible.)
In general, is it better to choose (non-const , const) over (const, non-const), or only in certain situations? Are there any reasons for picking one, or should I just choose one and stick with it?
Use a liberal dose of const whenever you can. For parameters, for functions. You are making a promise to the compiler (to be true to your design) and the compiler will help you along every time you digress with diagnostics. Make the most of your language features and compilers. Further, learn about const& (const-refernces) and their potential performance benefits.

Should const functionality be expanded?

EDIT: this question could probably use a more apropos title. Feel free to suggest one in the comments.
In using C++ with a large class set I once came upon a situation where const became a hassle, not because of its functionality, but because it's got a very simplistic definition. Its applicability to an integer or string is obvious, but for more complicated classes there are often multiple properties that could be modified independently of one another. I imagine many people forced to learn what the mutable keyword does might have had similar frustrations.
The most apparent example to me would be a matrix class, representing a 3D transform. A matrix will represent both a translation and a rotation each of which can be changed without modifying the other. Imagine the following class and functions with the hypothetical addition of 'multi-property const'.
class Matrix {
void translate(const Vector & translation) const("rotation");
void rotate(const Quaternion & rotation) const("translation");
}
public void spin180(const("translation") & Matrix matrix);
public void moveToOrigin(const("rotation") & Matrix matrix);
Or imagine predefined const keywords like "_comparable" which allow you to define functions that modify the object at will as long as you promise not to change anything that would affect the sort order of the object, easing the use of objects in sorted containers.
What would be some of the pros and cons of this kind of functionality? Can you imagine a practical use for it in your code? Is there a good approach to achieving this kind of functionality with the current const keyword functionality?
Bear in mind
I know such a language feature could easily be abused. The same can be said of many C++ language features
Like const I would expect this to be a strictly compile-time bit of functionality.
If you already think const is the stupidest thing since sliced mud, I'll take it as read that you feel the same way about this. No need to post, thanks.
EDIT:
In response to SBK's comment about member markup, I would suggest that you don't have any. For classes / members marked const, it works exactly as it always has. For anything marked const("foo") it treats all the members as mutable unless otherwise marked, leaving it up to the class author to ensure that his functions work as advertised. Besides, in a matrix represented as a 2D array internally, you can't mark the individual fields as const or non-const for translation or rotation because all the degrees of freedom are inside a single variable declaration.
Scott Meyers was working on a system of expanding the language with arbitary constraints (using templates).
So you could say a function/method was Verified,ThreadSafe (etc or any other constraints you liked). Then such constrained functions could only call other functions which had at least (or more) constraints. (eg a method maked ThreadSafe could only call another method marked ThreadSafe (unless the coder explicitly cast away that constraint).
Here is the article:
http://www.artima.com/cppsource/codefeatures.html
The cool concept I liked was that the constraints were enforced at compile time.
In cases where you have groups of members that are either const together or mutable together, wouldn't it make as much sense to formalize that by putting them in their own class together? That can be done today without changing the language.
Refinement
When an ADT is indistinguishable from itself after some operation the const property holds for the entire ADT. You wish to define partial constness.
In your sort order example you are asserting that operator< of the ADT is invariant under some other operation on the ADT. Your ad-hoc const names such as "rotation" are defined by the set of operations for which the ADT is invariant. We could leave the invariant unnamed and just list the operations that are invariant inside const(). Due to overloading functions would need to be specified with their full declaration.
void set_color (Color c) const (operator<, std::string get_name());
void set_name (std::string name) const (Color get_color());
So the const names can be seen as a formalism - their existence or absence doesn't change the power of the system. But 'typedef' could be used to name a list of invariants if that proves useful.
typedef const(operator<, std::string get_name()) DontWorryOnlyNameChanged;
It would be hard to think of good names for many cases.
Usefulness
The value in const is that the compiler can check it. This is a different kind of const.
But I see one big flaw in all of this. From your matrix example I might incorrectly infer that rotation and translation are independent and therefore commutative. But there is an obvious data dependency and matrix multiplication is not commutative. Interestingly, this is an example where partial constness is invariant under repeated application of one or the other but not both. 'translate' would be surprised to find that it's object had been translated due to a rotation after a previous translation. Perhaps I am misunderstanding the meaning of rotate and translate. But that's the problem, that constness now seems open to interpretation. So we need ... drum roll ... Logic.
Logic
It appears your proposal is analogous to dependent typing. With a powerful enough type system almost anything is provable at compile time. Your interest is in theorem provers and type theory, not C++. Look into intuitionistic logic, sequent calculus, Hoare logic, and Coq.
Now I've come full circle. Naming makes sense again,
int times_2(int n) const("divisible_by_3");
since divisible_by_3 is actually a type. Here's a prime number type in Qi. Welcome to the rabbit hole. And I pretended to be getting somewhere. What is this place? Why are there no clocks in here?
Such high level concepts are useful for a programmer.
If I wanted to make const-ness fine-grained, I'd do it structurally:
struct C { int x; int y; };
C const<x> *c;
C const<x,y> *d;
C const& e;
C &f;
c=&e; // fail, c->y is mutable via c
d=&e;
c=&f;
d=c;
If you allow me to express a preference for a scope that maximally const methods are preferred (the normal overloading would prefer the non-const method if my ref/pointer is non-const), then the compiler or a standalone static analysis could deduce the sets of must-be-const members for me.
Of course, this is all moot unless you plan on implementing a preprocessor that takes the nice high-level finely grained const C++ and translates it into casting-away-const C++. We don't even have C++0x yet.
I don't think that you can achieve this as strictly compile-time functionality.
I can't think of a good example so this strictly functional one will have to do:
struct Foo{
int bar;
};
bool operator <(Foo l, Foo r){
return (l.bar & 0xFF) < (r.bar & 0xFF);
}
Now I put a some Foos into a sorted set. Obviously the lower 8 bits of bar must remain unchanged so that the order is preserved. The upper bits can however be freely changed. This means the Foos in the set aren't const but aren't mutable either. However I don't see any way you could describe this level of constness in a general useful form without using runtime checking.
If you formalized the requirements I could even imagine, that you could prove that no compiler capable of doing this (at compile time) could even exist.
It could be interesting, but one of the useful features of const's simple definition is that the compiler can check it. If you start adding arbitrary constraints, such as "cannot change sort order", the compiler as it stands now cannot check it. Further, the problem of compile-time checking of arbitrary constraints is, in the general case, impossible to solve due to the halting problem. I would rather see the feature remain limited to what can actually be checked by a compiler.
There is work on enabling compilers to check more and more things — sophisticated type systems (including dependent type systems), and work such as the that done in SPARKAda, allowing for compiler-aided verification of various constraints — but they all eventually hit the theoretical limits of computer science.
I don't think the core language, and especially the const keyword, would be the right place for this. The concept of const in C++ is meant to express the idea that a particular action will not modify a certain area of memory. It is a very low-level idea.
What you are proposing is a logical const-ness that has to do with the high-level semantics of your program. The main problem, as I see it, is that semantics can vary so much between different classes and different programs that there would be no way for there to be a one-size-fits all language construct for this.
What would need to happen is that the programmer would need to be able to write validation code that the compiler would run in order to check that particular operations met his definition of semantic (or "logical") const-ness. When you think about it, though, such code, if it ran at compile-time, would not be very different from a unit test.
Really what you want is for the compiler to test whether functions adhere to a particular semantic contract. That's what unit tests are for. So what you're asking is that there be a language feature that automatically runs unit tests for you during the compilation step. I think that's not terribly useful, given how complicated the system would need to be.