javascriptlanguage-specifications

What part of ECMAScript spec mandates that String type is immutable?


I know that String primitive type in Javascript is immutable, via practice and word of mouth. But what combination of rules in the ECMA-262 makes it so? More specifically, why the second line in the following example silently does nothing?

const str = 'abc';
str[1] = '8';
console.log(str); // prints unmodified "abc", not "a8c".

Section 6.1.4 describes the internal composition of String datum. It does not contain anything about modifying the data, or at least I couldn't find anything after reading it thrice.

Section 13.15.2 describes the semantics of assignment. It does not contain any exceptions for any specific data type.

Section 13.3.2.1 describes the semantics of the property accessor operator. It does not contain any exceptions for any specific data type.

So, how exactly the string data type is defined to be immutable in Javascript?


Solution

  • The EMCAScript specification is silent about this, just as it is silent on object identity (i.e. object mutability). So yes, it's more about "via practice and word of mouth", but I guess a conforming implementation could change the memory representation of a string in the background (or even provide an API to do so as an extension).

    However, you can infer the immutability of strings from the phrasing of §6.1.4 "The String Type" that you linked:

    The String type is the set of all ordered sequences of zero or more 16-bit unsigned integer values (“elements”) up to a maximum length of 253 - 1 elements.

    This is a very mathematical definition, and in mathematics, values are always immutable. In addition, we can observe that there simply is no operation within ECMAScript that would mutate such a value.

    The definition applies only to primitive values though, not to String objects which wrap such a value and can have additional (mutable) properties. Again, there just is no operation that would change the [[StringData]] internal slot of a String instance. This is even explicitly described in the section on String Exotic Objects:

    A String object is an exotic object that encapsulates a String value and exposes virtual integer-indexed data properties corresponding to the individual code unit elements of the String value. String exotic objects always have a data property named "length" whose value is the number of code unit elements in the encapsulated String value. Both the code unit data properties and the "length" property are non-writable and non-configurable.

    This is also what you observe in your example code. The assignment str[1] = … goes to String's [[DefineOwnProperty]] internal method, which finds that the 1 property is non-writable, rejecting a change. The PutValue abstract operation will then throw an exception in strict mode (or ignore the failure in sloppy mode).