4

Not often but sometimes I need to use String.Trim() to remove whitespaces of a string.
If it was a longer time since last trim coding I write:

string s = " text ";
s.Trim();

and be surprised why s is not changed. I need to write:

string s = " text ";
s = s.Trim();

Why are some string methods designed in this (not very intuitive) way? Is there something special with strings?

brgerner
  • 4,287
  • 4
  • 23
  • 38

4 Answers4

24

Strings are immutable. Any string operation generates a new string without changing the original string.

From MSDN:

Strings are immutable--the contents of a string object cannot be changed after the object is created, although the syntax makes it appear as if you can do this.

Tudor
  • 61,523
  • 12
  • 102
  • 142
  • 1
    Thanks! I understand, immutability has its advantages. But then I would prever naming like `String.GetTrimmed()` to imply that there is no change. – brgerner Apr 17 '12 at 12:07
  • 1
    Except that once you know Strings are immutable, all those extra Get...ed become redundant. – Almo Apr 17 '12 at 12:13
  • 1
    @Almo: Exactly, string immutability is already a well known characteristic of both C# and Java. No one really expects something else. – Tudor Apr 17 '12 at 12:14
  • 2
    Lots of people expect something else! Many programmers have a hard time becoming accustomed to string immutability; I've seen statements like `s.Trim()` in code written even by experienced programmers. I daresay there'd be far less of that if @brgerner's suggestion had been implemented. – phoog Apr 17 '12 at 13:17
7

s.Trim() creates a new trimmed version of the original string and returns it instead of storing the new version in s. So, what you have to do is to store the trimmed instance in your variable:

  s = s.Trim();

This pattern is followed in all the string methods and extension methods.

The fact that string is immutable doesn't have to do with the decision to use this pattern, but with the fact of how strings are kept in memory. This methods could have been designed to create the new modified string instance in memory and point the variable to the new instance.

It's also good to remember that if you need to make lots of modifications to a string, it's much better to use an StringBuilder, which behaves like a "mutable" string, and it's much more eficient doing this kind of operations.

JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • `StringBuilder` does not have a `Trim()` method. But the `Replace(...)` methods do both: change object itself and return a `StringBuilder` object. – brgerner Apr 17 '12 at 12:21
  • Yes, you don't have a Trim, but you can also use `Remove()` or change the `Lenght` of the StringBuilder. i think you can't simulate a Trim with Replace. – JotaBe Apr 17 '12 at 12:27
  • A few quibbles: (1) Trim "trims the string" and "returns the trimmed string": this could lead the naïve reader to conclude that strings are mutable. (2) The pattern of returning an instance from an instance method is *possible* with mutable types, but *necessary* with immutable types. It's therefore not accurate to say that string immutability "doesn't have to do with the decision to use this pattern". (to be continued) – phoog Apr 17 '12 at 13:13
  • (continued) (3) The methods could not have been designed to "point the variable to the new instance" because C# does not have such semantics: no reference type stores a new instance in the receiver of an instance method call. With value types you can assign `this = something;` in an instance method, but not with reference types. – phoog Apr 17 '12 at 13:13
  • 1)corrected my redaction 2)`+=` changes the string pointed to by the calling variable. (3) `StringBuilder.Append("x)` changes the content of the StringBuilder in an instance method. Doesn't it? A string, according to C# language reference is just a sequence of 0 or more chars. Why couldn't this class change them? Making string inmutable is a design decision. Returning a new instance of string instead of assigning it to the caller variable is a decision design. 4) If you had the source code for string, couldn't you change Trim() so that it changes the content of the class itself? – JotaBe Apr 17 '12 at 13:56
  • The fact that they designed the String class to be immutable does indeed influence how this behaves. "This methods could have been designed to create the new modified string instance in memory and point the variable to the new instance." is not possible without changing the C# language. – nos Apr 18 '12 at 06:42
  • What exact language elements should be changed? I really can't guess it. – JotaBe Apr 18 '12 at 09:51
  • @JotaBe Well, when you do `s.Trim()` , there is no construct in C# that enables the code inside `Trim()` to make `s` reference a new instance. – nos Apr 18 '12 at 20:55
  • Maybe I didn't use the right word when I said instance. I should have told to a "different sequence of characters". Why can we think of string as a class that contains a private field of type array of characters? If so, couldn't an instance method modify this array of characters, or event dispose of this array of characters and point to a new one? As far as I know, String is a class, and, one of the OOP principles is encapsulation, or freedom to implement the private part of the class in any way. So what avoids from changing a string in this way, apart from a design decision? – JotaBe Apr 18 '12 at 23:26
  • I have just reviewed String implementation: is implemented in C++. A comment taken from the original source code: 'For Information on these methods, please see COMString.cpp The String class represents a static string of characters. Many of the String methods perform some type of transformation on the current instance and return the result as a new String. All comparison methods are implemented as a part of String. As with arrays, character positions (indices) are zero-based.' The "current instance" is an array of chars (native). So the pointer could be changed to point to the new buffer – JotaBe Apr 19 '12 at 00:10
  • @JotaBe Ofcourse. But that is a *mutable* string. And the C# creators decided to make strings immutable. If you're just creating a new internal array and pointing that array to something else, it would make strings mutable. And since they decided strings are immutable, they can't make one of the methods mutable, it's all or nothing. In the approach you're describing, `String a = "abcd"; String b = a; a.Trim();` cannot only affect `a` in C# (ok, they could make it a struct + copying)., it would affect `b` as well. But,`a.Trim()` cannot by definition change `a` and still call itself immutable. – nos Apr 19 '12 at 19:11
2

As it is written in MSDN Library:

A String object is called immutable (read-only), because its value cannot be modified after it has been created. Methods that appear to modify a String object actually return a new String object that contains the modification.

Because strings are immutable, string manipulation routines that perform repeated additions or deletions to what appears to be a single string can exact a significant performance penalty.

See this link.

Habib
  • 219,104
  • 29
  • 407
  • 436
gliderkite
  • 8,828
  • 6
  • 44
  • 80
1

In addition to all the good answers, I also feel that the reason being Threadsaftey.

Lets say

string s = " any text "; s.Trim();

When you say this there is nothing stopping the other thread from modifying s. If the same string is modified, lets say the other thread remove 'a' from s, then what is the result of s.Trim()?

But when it returns the new string, though it is being modified by the other thread, the trim can make a local copy modify it and return modified string.

Sandeep
  • 7,156
  • 12
  • 45
  • 57
  • 1
    Inmutable classes are thread safe by definition. If the class wasn't inmutable it wouldn't be thread safe unless you implemented the necessary locks. I want to change your question. If thread a does this: `string s = " any text "; s = s.Trim();` And thread b does this `s += "and more";` What is s in the end? Thread safety depends on what you do, not only on the class design itself. – JotaBe Apr 17 '12 at 14:02