This is hard to answer in isolation. A lot depends on the overall design of your language and the goals you want to reach. To quote Bjarne Stroustrup quoting Dennis Ritchie: “There are two kinds of programming languages: The ones that want to solve a problem and the ones that want to prove a point.”
Which of the two is yours? What problem do your future users have now that you want to solve with the new language’s constness system? Or what’s the point you want to prove with the constness system? Answering that will probably make the best course of action a lot clearer.
And now for a few hopefully helpful musings.
Is variable qualifier technically possible at all?
I don’t see any reason why it shouldn’t be. Roughly it boils down to the question of where to keep track of the information.
What are the advantages and disadvantages of variable qualifier?
There is at least one significant disadvantage. If you attach constness to the variable you pull it out of the type system proper. That makes the type system less expressive and leads me to a follow-up question to your template example: How would you model something like variant<T, const U, const V>
? Making everything const by default – although an attractive idea in general – doesn’t help here either. The question then just reverses to: How do you model a variant<mutable T, U, V>
? In the end, type based meta programming would be less powerful overall.
I have a hard time to come up with any significant advantage of making const a variable qualifier. I was thinking along the lines of simpler type-based matching algorithms at first. But that doesn’t work. If you don’t want to punch huge holes in your const correctness, there’s no way around including it when searching for matching types. I have a feeling that most (all?) other potential advantages will fail for the same reason.
Are these really advantages and disadvantages as stated? That depends entirely on the goals of your language. Even throwing out constness altogether can be the right choice. Just look at Python.
Maybe both options are useful.
Two kinds of constness are in play, so maybe you want to use both attachement points. One kind of constness is a property of the object type itself. Nobody is allowed to mutate, period. In C++:
void mutable_foo(Type& t);
int main() {
const Type t; // constant object
mutable_foo(t); // non-constant usage: does not compile
}
The other kind of constness is a property of the usage of an object. It’s a way to selectively restrict mutable access. In C++:
void const_foo(const Type& t);
int main() {
Type t; // non-constant object
const_foo(t); // constant usage: compiles ok
}
You could make object constness a part of the object’s type and usage constness a property of the variable. That way you still have access to the full type of the original object inside the function. In contrast in C++ there is no way to determine whether the underlying object of a const& argument is const itself or not.
Another idea to use both attachment points would be to control rebindability of variables. In C++ that would be the difference between a const pointer and a pointer to const. Could something similar be useful for values, too?
Both ideas aim at finer grained control over different aspects of and different targets for constness. From the theoretical and language design side there’s definitely a lot to explore here. From the practical programmer’s side, I don’t have an immediate application in mind for such a level of control. But I’m anything but objective in that regard.
const int * const
, the "variable qualifier" alone seems insufficientconst
mixes two aspects of constness: 1) “You are not allowed to modify this object in the current operation” (think const& function parameter) and 2) “This object is a constant that cannot be modified by anybody” (think string literal). How do you plan to handle those two aspects? That choice might very well impact the choice in question, too.mut
(which is basically "reverse const") is more part of the variable (or, in the case of references, the reference type rather than the referenced type) than the type.