2

I am planning to design a programming language. One challenge I face with is whether it is a good idea to have const as a variable qualifier instead of a type qualifier.

For example in C++:

const int x = 5;

means that x is of type const int.

While in my language, H++, the variable x is a const and its type is int.

This will impact the AST design:

| const as a variable qualifier | const as a type qualifier  |
|                               |                            |
| x:                            | x:                         |
|     const:  true              |     type: T                |
|     type: T                   |                            |
|                               | T:                         |
| T:                            |     typename: int          |
|     typename: int             |     const: true            |

Besides the AST design, it will impact the templates too. For example:

template<typename T>
void myfunc(T arg)
{
    ...
}

Now, depending on whether const a variable property or type property, the value of T will be different. If const is a variable property, T = int while if it is a type property, then T = const int. I am not sure whether this is a good idea or not.

Questions:

  • Is variable qualifier technically possible at all?
  • What are the advantages and disadvantages of variable qualifier?
  • Is there any commonly known programming language which has const or the other qualifier as a variable qualifier instead of type?
9
  • Do you want attempts to modify a const to be run time or compile time errors? Jun 28, 2020 at 7:26
  • @candied_orange, very good question. Currently, I plan the language to check the types at the compile time. However, I am keen to know how runtime type check will be influenced too.
    – Andrea
    Jun 28, 2020 at 7:33
  • 3
    You you want to support something like const int * const, the "variable qualifier" alone seems insufficient
    – Mat
    Jun 28, 2020 at 7:57
  • C++’s const 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.
    – besc
    Jun 28, 2020 at 8:01
  • 1
    You could look at Rust, where 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. Jun 28, 2020 at 11:08

4 Answers 4

4

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.

2

The problem is that const applied to the type of a variable means immutable (equivalent: readonly+no_mutable_references (C restrict pointers satisfy the latter)) in C++, but if you take a reference, it means readonly.

If you add immutable to the type-system, you will no longer have to throw immutable and readonly together when passing it on, and knowing the declared type of a variable is no longer that special.

So, upgrade the type-system, instead of trying to fit 3 possible states into a single bit and failing miserably.

0

Take Swift. Every variable is declared using one of the keywords “let” or “var”. The difference is that a “let” must be initialised exactly once before any use, and must not be initialised twice, and a “var” must be initialised at least once before any use.

Variables can contain values or references. A “let” reference means the reference cannot be changed (the variable refers to the same object once initialised), but the object can be modified. There’s no such thing as “reference to const object”.

Instance variables are also either “let” or “var”. Since all instance variables must be initialised in the constructor, “let” instance variables must be initialised exactly once in the constructor.

Methods of value types cannot modify the value unless marked as “mutating”, and mutating methods must only be called for “var” values. Methods of reference types are always allowed to modify the object.

There are officially no immutable types. In practice, a value or reference type may have no non-private “var” instances, and no methods that could modify the value or object after the constructor is run, which would mean the value or object is in practice immutable. But there is no way to declare a type as immutable.

-1

C++ supports const qualifier for both type and variable. Here you can control constness for object reference and data. But Java supports only type qualifier final. So based on your use case you can decide what you want. Edited:

int x = 4;
int y = 6;
Ex1:
const int * var1 : declares that var1 is a variable pointer to a constant int. 
*var1 = 5 // error (value constant) 
 var1 = &y // correct 
EX2: 
int * const var2 = &x : declares that var2 is const pointer to a variable int 
   var2 = &y // error (reference constant) 
   *var2= 5 // correct 
EX3: 
int const * const var3 = &x: declares that var3 is const pointer to a const int. 
   *var3 = 5 //error 
    var3 = &y // error
2
  • 1
    Can you please explain more? How C++ supports both ways. Can you also please provide examples?
    – Andrea
    Jun 28, 2020 at 10:58
  • @NeerajBansal You should edit that into your answer and not leave it as a comment. As it stands it is very hard to decipher what you actually wrote.
    – Peter M
    Jul 3, 2020 at 20:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.