38

I've often seen the terms immutable and const used interchangeably. However, from my (little) experience, the two differ a lot in the 'contract' they make in code:

Immutable makes the contract that this object will not change, whatsoever (e.g. Python tuples, Java strings).

Const makes the contract that in the scope of this variable it will not be modified (no promise whatsoever about what other threads might do to the object pointed to during this period, e.g. the C/C++ keyword).

Obviously, the two are not equivalent, unless the language is single-threaded (PHP), or has either linear or uniquness typing system (Clean, Mercury, ATS).

First, is my understanding of these two concepts correct?

Second, if there is a difference, why are they almost exclusively used interchangeably?

gnat
  • 21,442
  • 29
  • 112
  • 288
K.Steff
  • 4,475
  • 2
  • 31
  • 28
  • 4
    `const` doesn't exist in every language, and mutability and immutability doesn't exist in every language so making this *language agonistic* is not applicable. It is language **specific** only where these concepts apply. –  May 21 '12 at 23:45
  • 2
    Related, recommended reading: [Kinds of Immutability](http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx) (a few C# examples, but largely language-agnostic). Someone give Eric Lippert a medal. –  May 22 '12 at 11:08
  • The above link is dead. Here is that article in [Eric Lippert's blog](https://ericlippert.com/2007/11/13/immutability-in-c-part-one-kinds-of-immutability/ "Immutability in C# Part One: Kinds of Immutability | Fabulous adventures in coding") – Ooker Jun 02 '23 at 07:19

8 Answers8

22

Speaking for Java where the keyword "final" represents "const", consider:

final Person someone = new Person();

This means someone can NEVER refer to another Person object. But, you can still change details of the person being referred. E.g. someone.setMonthlySalary(10000);

But, if someone was an "Immutable" object, one of the following would be true: (a) You would not have a method named setMonthlySalary (b) Calling setMonthlySalary would always throw an exception such as UnsupportedOperationException

rationalrevolt
  • 329
  • 1
  • 2
18

I’ll speak to C++, where this difference is most relevant.

As you correctly note, immutable means that an object cannot change at all after its creation. This creation can of course occur at runtime, i.e., a const object is not necessarily a compile-time constant. In C++, an object is immutable if (1) and either (2) or (3) are met:

  1. It has no members declared mutable that are mutated by const member functions

  2. It is declared const

  3. const member functions do not use const_cast to remove const qualification in order to mutate any members

However, you could also consider access modifiers: if an operation internally mutates an instance, but has no effect on the state of the instance observable through its public interface, then the object is “logically immutable”.

So C++ provides the tools necessary to create immutable objects, but like most everything in C++, the tools are only minimally sufficient, and require diligence to actually use. The state of an instance is not necessarily confined to the instance member variables—because C++ does not provide a way to enforce referential transparency, it can include global or class state as well.

const also has another function in C++: to qualify references and pointers. A const reference may refer to a non-const object. It is legal (though not generally necessary or advisable) to use const_cast to mutate an object through a const reference, if and only if that object is declared non-const:

int        i = 4;         // Non-const object.
const int* p = &i;        // Pointer to a constant integer.

*const_cast<int*>(p) = 5; // Legal.

And of course it’s undefined behaviour to mutate a const object:

const int  i = 4;         // const object.
const int* p = &i;        // Pointer to a const integer.

*const_cast<int*>(p) = 5; // Illegal.
Jon Purdy
  • 20,437
  • 7
  • 63
  • 95
  • Simply put: There is **NO** mechanism in C++ that can protect an array from being modified. **PERIOD** – daparic Apr 18 '20 at 23:02
  • @typelogic Nothing in C++ lets you modify elements of `const int nums[] = { 1, 2 );` If you think you have a program that does, it isn't C++ – Caleth May 23 '20 at 21:44
  • @Caleth Huh? There are several shoot-myself-in-the-foot ways to modify your `const int nums` array that are perfectly valid C++. Not this-is-a-good-idea C++, but nonetheless valid C++. – Will Sep 15 '20 at 08:11
  • @Will no, the standard forbids modifying `const` objects, under pain of undefined behaviour. You don't have a C++ program when you ignore "A program shall ..." – Caleth Sep 15 '20 at 08:17
  • @Caleth Are you implying that even though I can show you source code that modifies a const array without throwing any warning or error in the latest versions of G++ or Visual Studio with --std=c++17 and strict checking, such a program isn't "really" C++? Because in that case, you are quite pedantic, but admittedly also technically correct, I suppose... – Will Sep 15 '20 at 08:24
  • @Caleth I agree with your assessment. A program is generally defined as a set of instructions and data that is given to a CPU to perform computations and instructions that will produce some output or none at all. Even if your build tools generate "warnings" and successfully generate binaries an executable, the build process being a success that gives you a direct translation to native assembly, pure binary that your processor can run is a defined program. Like everything else in life, there is good and bad. It may be ill-formed, but it is still a program. What it will do, that is undefined. – Francis Cugler Feb 15 '21 at 05:14
  • @Caleth There is more to be said about that. Now, an ill formed program most will claim is most definitely not production code and to some sentiments I can agree. However, just because it is ill-formed doesn't mean it doesn't have its uses. It would be no good for practical use in the consumer world of things such as appliances, vessels, traffic signals and controllers, etc... as it will put peoples lives at risk, yet as for academic, research and curiosity reasons, there is nothing wrong with that all. Now, if one can use it as a platform to learn and discover from, it becomes a product. – Francis Cugler Feb 15 '21 at 05:21
  • @Caleth If it can be taught it can be sold. If it can be sold it becomes a product. Then it surely must be production code after all! – Francis Cugler Feb 15 '21 at 05:23
  • @FrancisCugler I said "You don't have a C++ program", not "You don't have a program" – Caleth Feb 15 '21 at 08:45
  • @Caleth Yes, but it's still a program that was written in C++ compiled and executed on the processor... Now, if it will produce UB, crash, or yield wrong results, that's to be determined... it would be an ill-formed C++ program, not within the practical use variety of applications as production code, but can still be a product in regards to teaching, exploring, etc... One can write a book on C++ with nothing but ill-formed programs and breaking them down and explaining why they are ill-formed, and then show how to correct or circumvent them, so that their readers can learn the pitfalls of C++. – Francis Cugler Feb 15 '21 at 09:02
  • @FrancisCugler No, you've *tricked* a C++ *implementation* into producing an executable. – Caleth Feb 15 '21 at 09:06
  • @Caleth Well that depends on the Compiler and Linker too... some things are implementation defined by the standard... one trick that may work on one compile may not work on others... one thing may produce UB on one compiler but may not on others... If you have compiler errors or build errors you have NO program, it failed the build process. If you have warnings only, then it passes the build process. – Francis Cugler Feb 15 '21 at 09:52
  • 2
    @FrancisCugler UB does not have to "crash or give wrong results". An implementation *may* do what you expect with a program with undefined behaviour. – Caleth Feb 15 '21 at 09:56
  • @Caleth I know that, I mentioned all three because any of them can happen pending on compiler and version, and also the hardware and OS may have some affect on it too... That's why I called them ill-formed! They are improper! Now, if you're writing code for the everyday world of things, then yes stick with the Standard as well as with your Compiler's documentations and specifications.Here's an example or an analogy... Back in the 80's with the NES that used the 6502, there were several machine op codes that were undefined, yet people tested them and ended up using them in production games. – Francis Cugler Feb 15 '21 at 10:01
  • @Caleth Although they were written in Assembly or C turned to Assembly instead of C++, but the concept is still the same. – Francis Cugler Feb 15 '21 at 10:02
  • No, the concept is not the same. You can't get [time-travel](https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633) when you use an undefined op-code – Caleth Feb 15 '21 at 10:05
12

First, is my understanding of these two concepts correct?

Yes but your second question shows that you don't understand these differences.

Second, if there is a difference, why are they almost exclusively used interchangeably?

const in C++ is only used for access level (it means "read-only"), not for immutability. It imply that the access itself is totally separate from the data. For example you could manipulate some data then expose it through a const reference. The access is read-only, but the data itself, as all the datam is mutable.

const only garantee access limitations, while immutability (like in D for example) imply really no way to change the data at whatever stage of the life of the object.

Now, you can simulate immutability in C++ by making sure some data are not possible to be accessed in any other way than const and make sure it is initialized then not touched anymore. But that's not a strong guarantee as languages like D gives you when you mark your data as immutable. The language make sure it is not possible at all to do any operation modifying that data, while in C++ you are still potentially able to change the data through const casting and mutability if really necessary.

In the end, it is not the same at all as it don't offer at all the same guarantees.

Klaim
  • 14,832
  • 3
  • 49
  • 62
  • 1
    I like this answer because it is understandable, compared to the accepted one which talks a lot and then self-contradicts what it talks. Simply put, there is no mechanism in C++ that can protect an array from being modified. The pretention of `const` loses its meaning as soon as it is casted to something else because the function API requires it. – daparic Apr 18 '20 at 23:01
10

Immutable objects are those that does not change state after creating it. For example;

string prefix = "Pre";
string postfix = "Post";
string myComplexStr = prefix + postfix;

In this example myComplexStr object is immutable but not constant because it's value is calculated. And it is immutable because it is a string and has a static length property and cannot change.

Const objects are generally used to identify some real constants whose values are known before compilation like Pi, "USA", "StackOverflow.com", port numbers and so on.

From this perspective Const is different from Immutable objects because their values are not calculated by the program.

But if you are talking about "const" keyword in C++, you can say that "const" is used to create immutable objects.

Mert Akcakaya
  • 2,089
  • 1
  • 13
  • 16
  • 1
    const in C++ don't create immutable objects, it's only an access level. – Klaim May 22 '12 at 10:18
  • Can you explain how "const double pi = 3.14" is not immutable? – Mert Akcakaya May 22 '12 at 10:38
  • Well it depends on where it is. Lets say I do : "double* p_pi= const_cast( &pi ); *p_pi = 42;" for example. Then if pi is in the global space or namespace, I get a segmentation fault, but it is, I believe, undefined behaviour, not a specific error. If pi is a member of any object that is available at runtime, that are not static, I get pi == 42. You see, even using mutable is available because const in C++ is about access level, semantic, not data immutability, that is almost impossible to achieve in C++. You can only "simulate" it. const is not immutable. – Klaim May 22 '12 at 10:57
  • 3
    @Klaim Mutating a `const` like that is undefined behaviour no matter where it's allocated, IIRC. And undefined behaviour is *worse* than any specific error guaranteed to happen. It means you don't use C++ any more - C++ provides no means to change a `const` value (except `mutable` members of course, but that isn't your point), so as far as C++ is concerned, you cannot do it. What specific implementations happen to allow is another matter entirely (and I bet you, if you compile with optimizations, the stunt you pulled won't affect later expressions using `pi` because it's been substituted). –  May 22 '12 at 11:04
  • "const in C++ don't create immutable objects" is still wrong because it still creates global constants as you stated in your own answer. The keyword is ofcourse semantic at some level, otherwise you could always just manually change a memory cell's voltage and change an immutable object's value if you are so eager to even use undefined behaviours. – Mert Akcakaya May 22 '12 at 11:05
4

Speaking of JavaScript, the key words const and Object.freeze

const applies to bindings variables. It creates an immutable binding, you cannot assign a new value to it.

Object.freeze works on object values. It makes an object immutable. Namely, you cannot change its properties.

zangw
  • 141
  • 5
1

In C, C++ and related languages, there is also a difference between an object being const and your reference or pointer to the object being a constant reference.

If you try to modify a constant object you get undefined behaviour. (You can try to modify a constant object for example by taking its address, casting the address to a non-const pointer, and then using that non-const pointer to modify the object).

The constant pointer or reference on the other hand just tells the compiler that you cannot use this pointer or reference to modify the object. You can cast the pointer or reference and try to modify the object. If the object itself was constant, bad things will happen. If the object wasn't actually constant, it will change. This may of course confuse users of your code and quite possibly cause bugs.

In C, if you use a string literal like "Hello", the five chars and the trailing zero bytes are actually constant, but you get a non-const pointer. Very bad idea to use that non-const pointer to change the object.

In C, you can have a "const restrict" pointer. That means the object pointed to is temporarily constant. If the object is modified by any means while the "const restrict" pointer is in scope, you get undefined behaviour. This is stronger than a const pointer which only prevents you from changing an object through this pointer.

gnasher729
  • 42,090
  • 4
  • 59
  • 119
-1

In C++ they are the same. Although you can change a const object if you have it's location in memory and OS permission to write to that memory.

Martin Beckett
  • 15,776
  • 3
  • 42
  • 69
  • 3
    Actually that's an argument *against* them being the same: C++ simply has no immutable keyword or language support. And also, I'm assuming that the programmer utilises the language in a sane manner: otherwise, const, too, has absolutely no value. – K.Steff May 21 '12 at 23:21
  • 2
    @K.Steff - perhaps better to say there is no extra immutable-ness in C++ other than provided by const – Martin Beckett May 21 '12 at 23:23
  • Absolutely precise :) – K.Steff May 21 '12 at 23:25
  • In C++ they are not the same at all. const is "read-only" access level, it don't mean that the data is immutable. You can bypass it in C++, most of the time. – Klaim May 22 '12 at 10:58
  • `const` then is a next-to-useless construct. It does not and cannot, and can never, protect the array from being modified. – daparic Apr 18 '20 at 22:54
  • @typelogic what's useless about knowing that a particular call isn't going to modify the value you pass to it? And you absolutely can have immutable arrays in C++ – Caleth May 23 '20 at 21:55
-1

Consider an object of a example class as "ex", ex is a variable refering to object of class example Constant : means you cannot change the value of variable ex Immutable : means you cannot edit the object, i.e. you cannot change any of the data inside that object

Consider, Class fruit{ Color and size}mango;

If object mango is immutable you cannot change the colour and size but you can do mango = another_fruit_object While if mango is constant you cannot assign any other value to mango but you can change colour and size.

Hope you understand the example.