C
C#6mo ago
Tarkacode

String : Immutable reference type

Hello! I don't understand something in C#, and I would love to have some guidance. In the following code, the variable storing the string called "status" still has the value "Healthy" when outside the method scope.
string status = "Healthy";

Console.WriteLine($"Start: {status}");
SetHealth(status, false);
Console.WriteLine($"End: {status}");

void SetHealth(string status, bool isHealthy)
{
status = (isHealthy ? "Healthy" : "Unhealthy");
Console.WriteLine($"Middle: {status}");
}
string status = "Healthy";

Console.WriteLine($"Start: {status}");
SetHealth(status, false);
Console.WriteLine($"End: {status}");

void SetHealth(string status, bool isHealthy)
{
status = (isHealthy ? "Healthy" : "Unhealthy");
Console.WriteLine($"Middle: {status}");
}
Prints :
Start: Healthy
Middle: Unhealthy
End: Healthy
Start: Healthy
Middle: Unhealthy
End: Healthy
And I would love to understand why. If the string status is passed as a reference type in the method "SetHeatlh", it means that "status" called in the method as an argument, is a variable with the address of the string "Healthy" somewhere in the Heap. When the method says
status = (isHealthy ? "Healthy" : "Unhealthy");
status = (isHealthy ? "Healthy" : "Unhealthy");
Should it not mean that a new string with value "Unhealthy" is created on the Heap, and then the variable "status" should store the new address of this new string object in itself as a variable? Why is the address of the status not changed when we go out of the method SetHealth? I thought any change on an reference type variable inside a method should be saved outside of this method? Any help gladly appreciated 👍
21 Replies
Jimmacle
Jimmacle6mo ago
if you want to modify the variable itself being passed (like setting it to an entirely different value), you need to pass it as ref this applies to all variable types, not just strings
Sir Rufo
Sir Rufo6mo ago
When you assign a new value to a string variable then you create a new instance and store that reference in the variable.
Tarkacode
Tarkacode6mo ago
Oh, so thats because its an entirely new address ? And if i changed the Color of a Car in a method (by passing the car as an argument), it would save the new color of the Car because it is still the same address to the car?
Sir Rufo
Sir Rufo6mo ago
You change a property of an instance of the car which will not change the reference
Jimmacle
Jimmacle6mo ago
if you have C experience, string status is like a char* and ref string status would be like a char** (ignoring constness)
Tarkacode
Tarkacode6mo ago
Ok i think i understand better but i have still a question, but I need to write some code before Unfortunately i don't have C experience 😁 Ok nice, I understand now, many thanks!
Car car = new();
Console.WriteLine("Start : " + car.Color);

SetColorToWhite(car);

Console.WriteLine("End : " + car.Color);

void SetColorToWhite(Car car)
{
car = new Car();
car.Color = "white";
Console.WriteLine("Medium : " + car.Color);
}

public class Car
{
public string Color { get; set; } = "black";
}
Car car = new();
Console.WriteLine("Start : " + car.Color);

SetColorToWhite(car);

Console.WriteLine("End : " + car.Color);

void SetColorToWhite(Car car)
{
car = new Car();
car.Color = "white";
Console.WriteLine("Medium : " + car.Color);
}

public class Car
{
public string Color { get; set; } = "black";
}
I didn't know that a code like this would not save the changes to Car ^^' It prints
Start : black
Medium : white
End : black
Start : black
Medium : white
End : black
I tought I would not learn anything new with the freecodecamp C# certification in partnership with Microsoft, but they proved me wrong fortunately
Sir Rufo
Sir Rufo6mo ago
Why should it save the changes to car? I give you my black car. You buy yourself a new black car and paint it white. How on earth should my car also get white?
Tarkacode
Tarkacode6mo ago
Idk, I thought that because the variable "car" is a global variable, any change to that global variable would be saved since its a reference type But as you say it, it makes perfect sense now that it doesn't change
Angius
Angius6mo ago
No such thing as "global" in C# Unless, idk, a static property of a class maybe But even then it's not global global
Tarkacode
Tarkacode6mo ago
Ok so its a top level statement variable
Angius
Angius6mo ago
Your top-level code gets wrapped into a class and a method
Tarkacode
Tarkacode6mo ago
And it would work the same if it was a class member, right?
Angius
Angius6mo ago
var foo = "hello";
var foo = "hello";
becomes
internal class Program
{
public static void Main(string[] args)
{
var foo = "hello";
}
}
internal class Program
{
public static void Main(string[] args)
{
var foo = "hello";
}
}
Tarkacode
Tarkacode6mo ago
Oh yes, so its not even a class member then Its just a local variable?
Angius
Angius6mo ago
Yep
Tarkacode
Tarkacode6mo ago
Ok thank you 😄
Jimmacle
Jimmacle6mo ago
you actually have 2 variables called car in this code one in the top level statements part, another in the method they aren't the same variable
Tarkacode
Tarkacode6mo ago
How can it be? I pass it as an argument and i don't declare a new variable in the method, and yet they are still not the same variable? Or is the parameter declaration considered as a variable declaration?
cap5lut
cap5lut6mo ago
one car variable is ur local top level statement variable, the other car variable is the method parameter basically when u call SetColorToWhite(car);, a lot of stuff happens under the hood: first of all there will be stack allocation for everything the method needs (local variables of the method, method parameters and some more) after that the content of the variables u passed will be copied to the respective method parameter's address on the stack then the method will be executed. then everything stack allocated for the method will be released again
void SetColorToWhite(Car methodParameterCar)
{
methodParameterCar = new Car();
methodParameterCar.Color = "white";
}
void SetColorToWhite(Car methodParameterCar)
{
methodParameterCar = new Car();
methodParameterCar.Color = "white";
}
so here, at the first line, a new reference to a Car object will be stored in the method parameter methodParameterCar (what ever was in there before will be overwritten), which exists as long as the method is executed. and then its color is set to white. after the method finished execution, methodParameterCar does not exist anymore and the Car object is unreferenced and (sooner or later) garbage collected
void SetColorToWhite2(Car methodParameterCar)
{
methodParameterCar.Color = "white";
}
void SetColorToWhite2(Car methodParameterCar)
{
methodParameterCar.Color = "white";
}
here, in methodParameterCar is a copy of the reference to an Car object. upon execution the color of the object that is referenced is stored, and thus changes the object which u passed to the method
Tarkacode
Tarkacode6mo ago
Ok, I see
cap5lut
cap5lut6mo ago
with the afore mentioned ref, the story is a bit different. without it u pass a copy of the reference to the object of type Car around. with it, u pass a copy of the address to the variable/field of the reference to the object of type Car around