If a string is immutable, does that mean that....
(let's assume JavaScript)
var str = 'foo';
alert(str.substr(1)); // oo
alert(str); // foo
Does it mean, when calling methods on a string, it will return the modified string, but it won't change the initial string?
If the string was mutable, does that mean the 2nd alert() would return oo as well?
It means that once you instantiate the object, you can't change its properties. In your first alert you aren't changing foo. You're creating a new string. This is why in your second alert it will show "foo" instead of oo.
Does it mean, when calling methods on
a string, it will return the modified
string, but it won't change the
initial string?
Yes. Nothing can change the string once it is created. Now this doesn't mean that you can't assign a new string object to the str variable. You just can't change the current object that str references.
If the string was mutable, does that
mean the 2nd alert() would return oo
as well?
Technically, no, because the substring method returns a new string. Making an object mutable, wouldn't change the method. Making it mutable means that technically, you could make it so that substring would change the original string instead of creating a new one.
On a lower level, immutability means that the memory the string is stored in will not be modified. Once you create a string "foo", some memory is allocated to store the value "foo". This memory will not be altered. If you modify the string with, say, substr(1), a new string is created and a different part of memory is allocated which will store "oo". Now you have two strings in memory, "foo" and "oo". Even if you're not going to use "foo" anymore, it'll stick around until it's garbage collected.
One reason why string operations are comparatively expensive.
Immutable means that which cannot be changed or modified.
So when you assign a value to a string, this value is created from scratch as opposed to being replaced. So everytime a new value is assigned to the same string, a copy is created. So in reality, you are never changing the original value.
I'm not certain about JavaScript, but in Java, strings take an additional step to immutability, with the "String Constant Pool". Strings can be constructed with string literals ("foo") or with a String class constructor. Strings constructed with string literals are a part of the String Constant Pool, and the same string literal will always be the same memory address from the pool.
Example:
String lit1 = "foo";
String lit2 = "foo";
String cons = new String("foo");
System.out.println(lit1 == lit2); // true
System.out.println(lit1 == cons); // false
System.out.println(lit1.equals(cons)); // true
In the above, both lit1 and lit2 are constructed using the same string literal, so they're pointing at the same memory address; lit1 == lit2 results in true, because they are exactly the same object.
However, cons is constructed using the class constructor. Although the parameter is the same string constant, the constructor allocates new memory for cons, meaning cons is not the same object as lit1 and lit2, despite containing the same data.
Of course, since the three strings all contain the same character data, using the equals method will return true.
(Both types of string construction are immutable, of course)
The text-book definition of mutability is liable or subject to change or alteration.
In programming, we use the word to mean objects whose state is allowed to change over time. An immutable value is the exact opposite – after it has been created, it can never change.
If this seems strange, allow me to remind you that many of the values we use all the time are in fact immutable.
var statement = "I am an immutable value";
var otherStr = statement.slice(8, 17);
I think no one will be surprised to learn that the second line in no way changes the string in statement.
In fact, no string methods change the string they operate on, they all return new strings. The reason is that strings are immutable – they cannot change, we can only ever make new strings.
Strings are not the only immutable values built into JavaScript. Numbers are immutable too. Can you even imagine an environment where evaluating the expression 2 + 3 changes the meaning of the number 2? It sounds absurd, yet we do this with our objects and arrays all the time.
Immutable means the value can not be changed. Once created a string object can not be modified as its immutable. If you request a substring of a string a new String with the requested part is created.
Using StringBuffer while manipulating Strings instead makes the operation more efficient as StringBuffer stores the string in a character array with variables to hold the capacity of the character array and the length of the array(String in a char array form)
From strings to stacks... a simple to understand example taken from Eric Lippert's blog:
Path Finding Using A* in C# 3.0, Part Two...
A mutable stack like System.Collections.Generic.Stack
is clearly not suitable. We want to be
able to take an existing path and
create new paths from it for all of
the neighbours of its last element,
but pushing a new node onto the
standard stack modifies the stack.
We’d have to make copies of the stack
before pushing it, which is silly
because then we’d be duplicating all
of its contents unnecessarily.
Immutable stacks do not have this problem. Pushing onto an immutable
stack merely creates a brand-new stack
which links to the old one as its
tail. Since the stack is immutable,
there is no danger of some other code
coming along and messing with the tail
contents. You can keep on using the
old stack to your heart’s content.
To go deep on understaning immutability, read Eric's posts starting with this one:
Immutability in C# Part One: Kinds of Immutability
One way to get a grasp of this concept is to look at how javascript treats all objects, which is by reference. Meaning that all objects are mutable after being instantiated, this means that you can add an object with new methods and properties. This matters because if you want an object to be immutable the object can not change after being instantiated.
Try This :
let string = "name";
string[0] = "N";
console.log(string); // name not Name
string = "Name";
console.log(string); // Name
So what that means is that string is immutable but not constant, in simple words re-assignment can take place but can not mutate some part.
The text-book definition of mutability is liable or subject to change or alteration. In programming, we use the word to mean objects whose state is allowed to change over time. An immutable value is the exact opposite – after it has been created, it can never change.
If this seems strange, allow me to remind you that many of the values we use all the time are in fact immutable.
var statement = "I am an immutable value"; var otherStr = statement.slice(8, 17);
I think no one will be surprised to learn that the second line in no way changes the string in statement. In fact, no string methods change the string they operate on, they all return new strings. The reason is that strings are immutable – they cannot change, we can only ever make new strings.
Strings are not the only immutable values built into JavaScript. Numbers are immutable too. Can you even imagine an environment where evaluating the expression 2 + 3 changes the meaning of the number 2? It sounds absurd, yet we do this with our objects and arrays all the time.
Related
I would like to get a better understanding of what is actually going on when I find the length of a string. I tried looking on W3, ECMA, and at the V8 Ignition website but not much luck.
I keep reading that 'JavaScript treats primitive values as objects when executing methods and properties.' But, I can't seem to find out how exactly this happens. If I call a method/property on a primitive which, I assume gets interpreted as an object by Ignition, doesn't the String class need to call a function at some point to iterate the string? I feel like myString.length should be called a method and String.length could MAYBE be called a property, depending on at which point the "property" is found and how it's found.
Basically, I don't understand why it's touted as a property if it doesn't seem to be inherent and has to be fetched/determined. That seems like a method to me (let alone the fact that string.length) isn't even a real thing and is interpreted.
(V8 developer here.)
I can see several issues here that can be looked at separately:
1. From a language specification perspective, is something a method or a property?
Intuitively, the distinction is: if you write a function call like obj.method(), then it's a method; if you write obj.property (no ()), then it's a property.
Of course in JavaScript, you could also say that everything is a property, and in case the current value of the property is a function, then that makes it a method. So obj.method gets you a reference to that function, and obj.method() gets and immediately calls it:
var obj = {};
obj.foo = function() { console.log("function called"); return 42; }
var x = obj.foo(); // A method!
var func = obj.foo; // A property!
x = func(); // A call!
obj.foo = 42;
obj.foo(); // A TypeError!
2. When it looks like a property access, is it always a direct read/write from/to memory, or might some function get executed under the hood?
The latter. JavaScript itself even provides this capability to objects you can create:
var obj = {};
Object.defineProperty(obj, "property", {
get: function() { console.log("getter was called"); return 42; },
set: function(x) { console.log("setter was called"); }
});
// *Looks* like a pair of property accesses, but will call getter and setter:
obj.property = obj.property + 1;
The key is that users of this obj don't have to care that getters/setters are involved, to them .property looks like a property. This is of course very much intentional: implementation details of obj are abstracted away; you could modify the part of the code that sets up obj and its .property from a plain property to a getter/setter pair or vice versa without having to worry about updating other parts of the code that read/write it.
Some built-in objects rely on this trick, the most common example is arrays' .length: while it's specified to be a property with certain "magic" behavior, the most straightforward way for engines to implement this is to use a getter/setter pair under the hood, where in particular the setter does the work of truncating any extra array elements if you set the length to a smaller value than before.
3. So what does "abc".length do in V8?
It reads a property directly from memory. All strings in V8 always have a length field internally. As commenters have pointed out, JavaScript strings are immutable, so the internal length field is written only once (when the string is created), and then becomes a read-only property.
Of course this is an internal implementation detail. Hypothetically, an engine could use a "C-style" string format internally, and then it would have to use a strlen()-like function to determine a string's length when needed. However, on a managed heap, being able to quickly determine each object's size is generally important for performance, so I'd be surprised if an engine actually made this choice. "Pascal-style" strings, where the length is stored explicitly, are more suitable for JavaScript and similar garbage-collected languages.
So, in particular, I'd say it's fair to assume that reading myString.length in JavaScript is always a very fast operation regardless of the string's length, because it does not iterate the string.
4. What about String.length?
Well, this doesn't have anything to do with strings or their lengths :-)
String is a function (e.g. you can call String(123) to get "123"), and all functions have a length property describing their number of formal parameters:
function two_params(a, b) { }
console.log(two_params.length); // 2
As for whether that's a "simple property" or a getter under the hood: there's no reason to assume that it's not a simple property, but there's also no reason to assume that engines can't internally do whatever they want (so long as there's no observable functional difference) if they think it increases performance or saves memory or simplifies things or improves some other metric they care about :-)
(And engines can and do make use of this freedom, for various forms of "lazy"/on-demand computation, caching, optimization -- there are plenty of internal function calls that you probably wouldn't expect, and on the flip side what you "clearly see" as a function call in the JS source might (or might not!) get inlined or otherwise optimized away. The details change over time, and across different engines.)
Length is not a method, it is a property. It doesn't actually do anything but return the length of an array, a string, or the number of parameters expected by a function. When you use .length, you are just asking the JavaScript interpreter to return a variable stored within an object; you are not calling a method.
Also, note that the String.length property gives the actual number of code units in a string, rather than a literal character count. One code unit is 16 bits as defined by UTF-16 (used by JavaScript). However, some special characters use 32 bits which means that in a string containing one of these characters the String.length property might give you a higher character count than the literal number of characters.
Link:- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length
And also one fact length work very different with string.length from Array.length
let myString = "bluebells";
myString.length = 4;
console.log(myString); //bluebells
console.log(myString.length); //9
//--
let myArr = [5,6,8,2,4,7];
myArr.length = 2;
console.log(myArr); //[5, 6]
console.log(myArr.length); //2
I will reference to Mozilla's docs about String object.
JavaScript automatically converts primitives to String objects, so that it's possible to use String object methods for primitive strings. In contexts where a method is to be invoked on a primitive string or a property lookup occurs, JavaScript will automatically wrap the string primitive and call the method or perform the property lookup.
Good example of such situation would be accessing length property:
let word = "Hello";
word.length;
I have understood that what happens in this situation is:
let word = "Hello";
String(word).length;
But after trying some benchmarks it's clear for me that word.length is much faster than String(word).length. It seems that implicit conversion is something completely different than String(word), much faster. I cannot find any info about how this implicit conversion works, but it might be helpful to know in some optimization problems.
The reason for that is probably time to parse and the fact that inner JS string object (that is actually C++) works faster then creating extra interface to interact with string on high JS level...
So it's all about optimisation
There is good article about it (https://dev.to/promhize/what-you-need-to-know-about-javascripts-implicit-coercion-e23).
In Javascript numbers strings and booleans are said to be primitive types.
Primitive types are passed around by copy.
OK consider the following code:
var s1 = "this is a string of 1000 characters ...";
var s2 = s1; // (2)
What happens in line (2)? 1000 characters are copied to the variable s2?
OR is there one memory location and both s1 and s2 refer to this memory location?
I believe the second is true.
If so, why all books say that strings are primitive types, they are not, they are
reference types, aren't they?
What happens in line (2)? 1000 characters are copied to the variable s2? OR is there one memory location and both s1 and s2 refer to this memory location?
It is an implementation detail of the JavaScript engine, there is no way to tell the difference from inside the JavaScript program.
why all books say that strings are primitive types
The language defines them as such.
they are reference types, aren't they?
They might be implemented that way at a level lower then is exposed to JS, but that doesn't matter to the JS author.
What happens in line (2)?
That's more or less implementation defined. To you, it will look like a copy. However, the engine is free to optimise it, and probably will. No doubt, something like copy-on-write.
In JavaScript, there are primitive strings and string objects. It's worth knowing the differences. A string object is passed around by reference, but seeing as all string methods return a new string, you're unlikely to modify it.
Every time I assign a string, I'd actually like to assign a string object, without the extra code.
This var foo = "bar";
becomes var foo = new String("bar");
Basically hi-jacking the assignment.
Follow-up:
If the above is not possible is there a way to prototype the string variable type, rather than the String object?
As pointed out by armando, the foo would be a string type, but is essentially a customized array. It would be nice to be able to prototype functions to that class.
No this is not possible
If it was possible, you really would not want to do this, at least not globally.
The string variable type does not have all the extra overhead that an object does.
Note: the string array that is created (in your case, foo) would have other properties (eg foo.length)
Objects come at a performance hit
It's not quite what you're looking for, but you may want to look at Overriding assignment operator in JS
Does javascript use immutable or mutable strings? Do I need a "string builder"?
They are immutable. You cannot change a character within a string with something like var myString = "abbdef"; myString[2] = 'c'. The string manipulation methods such as trim, slice return new strings.
In the same way, if you have two references to the same string, modifying one doesn't affect the other
let a = b = "hello";
a = a + " world";
// b is not affected
However, I've always heard what Ash mentioned in his answer (that using Array.join is faster for concatenation) so I wanted to test out the different methods of concatenating strings and abstracting the fastest way into a StringBuilder. I wrote some tests to see if this is true (it isn't!).
This was what I believed would be the fastest way, though I kept thinking that adding a method call may make it slower...
function StringBuilder() {
this._array = [];
this._index = 0;
}
StringBuilder.prototype.append = function (str) {
this._array[this._index] = str;
this._index++;
}
StringBuilder.prototype.toString = function () {
return this._array.join('');
}
Here are performance speed tests. All three of them create a gigantic string made up of concatenating "Hello diggity dog" one hundred thousand times into an empty string.
I've created three types of tests
Using Array.push and Array.join
Using Array indexing to avoid Array.push, then using Array.join
Straight string concatenation
Then I created the same three tests by abstracting them into StringBuilderConcat, StringBuilderArrayPush and StringBuilderArrayIndex http://jsperf.com/string-concat-without-sringbuilder/5 Please go there and run tests so we can get a nice sample. Note that I fixed a small bug, so the data for the tests got wiped, I will update the table once there's enough performance data. Go to http://jsperf.com/string-concat-without-sringbuilder/5 for the old data table.
Here are some numbers (Latest update in Ma5rch 2018), if you don't want to follow the link. The number on each test is in 1000 operations/second (higher is better)
Browser
Index
Push
Concat
SBIndex
SBPush
SBConcat
Chrome 71.0.3578
988
1006
2902
963
1008
2902
Firefox 65
1979
1902
2197
1917
1873
1953
Edge
593
373
952
361
415
444
Exploder 11
655
532
761
537
567
387
Opera 58.0.3135
1135
1200
4357
1137
1188
4294
Findings
Nowadays, all evergreen browsers handle string concatenation well. Array.join only helps IE 11
Overall, Opera is fastest, 4 times as fast as Array.join
Firefox is second and Array.join is only slightly slower in FF but considerably slower (3x) in Chrome.
Chrome is third but string concat is 3 times faster than Array.join
Creating a StringBuilder seems to not affect perfomance too much.
Hope somebody else finds this useful
Different Test Case
Since #RoyTinker thought that my test was flawed, I created a new case that doesn't create a big string by concatenating the same string, it uses a different character for each iteration. String concatenation still seemed faster or just as fast. Let's get those tests running.
I suggest everybody should keep thinking of other ways to test this, and feel free to add new links to different test cases below.
http://jsperf.com/string-concat-without-sringbuilder/7
from the rhino book:
In JavaScript, strings are immutable objects, which means that the
characters within them may not be changed and that any operations on
strings actually create new strings. Strings are assigned by
reference, not by value. In general, when an object is assigned by
reference, a change made to the object through one reference will be
visible through all other references to the object. Because strings
cannot be changed, however, you can have multiple references to a
string object and not worry that the string value will change without
your knowing it
Just to clarify for simple minds like mine (from MDN):
Immutables are the objects whose state cannot be changed once the object is created.
String and Numbers are Immutable.
Immutable means that:
You can make a variable name point to a new value, but the previous value is still held in memory. Hence the need for garbage collection.
var immutableString = "Hello";
// In the above code, a new object with string value is created.
immutableString = immutableString + "World";
// We are now appending "World" to the existing value.
This looks like we're mutating the string 'immutableString', but we're not. Instead:
On appending the "immutableString" with a string value, following events occur:
Existing value of "immutableString" is retrieved
"World" is appended to the existing value of "immutableString"
The resultant value is then allocated to a new block of memory
"immutableString" object now points to the newly created memory space
Previously created memory space is now available for garbage collection.
Performance tip:
If you have to concatenate large strings, put the string parts into an array and use the Array.Join() method to get the overall string. This can be many times faster for concatenating a large number of strings.
There is no StringBuilder in JavaScript.
The string type value is immutable, but the String object, which is created by using the String() constructor, is mutable, because it is an object and you can add new properties to it.
> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }
Meanwhile, although you can add new properties, you can't change the already existing properties
A screenshot of a test in Chrome console
In conclusion,
1. all string type value (primitive type) is immutable.
2. The String object is mutable, but the string type value (primitive type) it contains is immutable.
Strings are immutable – they cannot change, we can only ever make new strings.
Example:
var str= "Immutable value"; // it is immutable
var other= statement.slice(2, 10); // new string
Regarding your question (in your comment to Ash's response) about the StringBuilder in ASP.NET Ajax the experts seem to disagree on this one.
Christian Wenz says in his book Programming ASP.NET AJAX (O'Reilly) that "this approach does not have any measurable effect on memory (in fact, the implementation seems to be a tick slower than the standard approach)."
On the other hand Gallo et al say in their book ASP.NET AJAX in Action (Manning) that "When the number of strings to concatenate is larger, the string builder becomes an essential object to avoid huge performance drops."
I guess you'd need to do your own benchmarking and results might differ between browsers, too. However, even if it doesn't improve performance it might still be considered "useful" for programmers who are used to coding with StringBuilders in languages like C# or Java.
It's a late post, but I didn't find a good book quote among the answers.
Here's a definite except from a reliable book:
Strings are immutable in ECMAScript, meaning that once they are created, their values cannot change. To change the string held by a variable, the original string must be destroyed and the variable filled with another string containing a new value...
—Professional JavaScript for Web Developers, 3rd Ed., p.43
Now, the answer which quotes Rhino book's excerpt is right about string immutability but wrong saying "Strings are assigned by reference, not by value." (probably they originally meant to put the words an opposite way).
The "reference/value" misconception is clarified in the "Professional JavaScript", chapter named "Primitive and Reference values":
The five primitive types...[are]: Undefined, Null, Boolean, Number, and String. These variables are said to be accessed by value, because you are manipulating the actual value stored in the variable.
—Professional JavaScript for Web Developers, 3rd Ed., p.85
that's opposed to objects:
When you manipulate an object, you’re really working on a reference to that object rather than the actual object itself. For this reason, such values are said to be accessed by reference.—Professional JavaScript for Web Developers, 3rd Ed., p.85
JavaScript strings are indeed immutable.
Strings in Javascript are immutable