3

I'm having trouble understanding what exactly the ref keyword in C# does. In my C++ code I am creating a string variable along with a pointer and reference variable pointing to it. I'm passing it to either a Delete or Change function, and as expected all 3 variables are being modified.

However, with C#, I'm creating variable x and initialising it with string data. I'm creating a variable y which should under the hood be a reference to x. I'm then passing x into the Change or Delete method with a ref keyword, causing the variable inside the method, as well as x to be modified. However, y is not modified, even though it should be a reference to x, just like in C++. This is not just an issue with strings either, as I have tried the above test with a C# object, and had the same results.

Does this mean y copied x by value when I executed var y = x?

C++

#include <iostream>
using namespace std;

void Delete(string &variable)
{
    variable = "";
}

void Change(string &variable)
{
    variable = "changed data";
}

void main()
{
    string x = "data";
    string *y = &x;
    string &z = x;
    Delete(x);
}

c#

namespace ConsoleApplication1
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var x = "data";
            var y = x;
            Change(ref x);
        }


        public static void Delete(ref string variable)
        {
            variable = null;
        }

        public static void Change(ref string variable)
        {
            variable = "changed";
        }
    }
}
Sharpiro
  • 2,305
  • 2
  • 18
  • 27
  • @mash: In that example, the LHS is being changed - in this example, the RHS is being changed. – Dave Doknjas Aug 03 '16 at 01:27
  • The issue is not with the 'ref' keyword - the issue is that y is not updated with x's value when x changes. – Dave Doknjas Aug 03 '16 at 01:31
  • Also consider using the 'out' keyword instead of 'ref' in C# (see:http://stackoverflow.com/questions/1516876/when-to-use-ref-vs-out) – Sal Aug 03 '16 at 01:44
  • You don't even need the 'Change' or 'Delete' method to show the behavior in C++. Just use "x = "foo"" instead of the method call, and you have the same scenario that cannot be reproduced in C#. – Dave Doknjas Aug 03 '16 at 01:48
  • @Paul: But that doesn't get to the core problem - in C# 'y' is unchanged after 'x' changes - there is no C# equivalent on a statement-by-statement basis. – Dave Doknjas Aug 03 '16 at 01:52

3 Answers3

3

This line: var y = x; makes y a copy of x and not a reference to x in c# so it was not suppose to change when you called Changed function.

There doesn't appear to be an easy way to reproduce the same C++ behavior in C# (or most other languages).

When you pass a non value type object as an argument to a function, the object is passed by value but the object content (properties/fields,etc..) are passed by reference(you can change them from inside the function), when you pass the object with the "ref" keyword, the object itself is byref and can also be changed, (its the same as sending a pointer vs sending a double pointer to a struct (wich itself holds pointers) in c++/c).

Dr.Haimovitz
  • 1,568
  • 12
  • 16
  • if `y` becomes a copy of `x', then how come if 'x' were an object with a string property named 'Value', and that object were passed to a function w/o the 'ref' keyword, and that function modified the 'Value' property. Why would the 'Value' property of both 'x' and 'y' be modified afterwards? If 'y' were copied by value, then wouldn't it be ignorant of changes made to 'x'? – Sharpiro Aug 03 '16 at 01:51
  • 1
    @Sharpiro: Without 'ref', changes to the internal state of the object are still allowed - only the object identity is unchanged after the method call. In other words, (without 'ref') the object is guaranteed to remain the same object, but the state can be modified. – Dave Doknjas Aug 03 '16 at 01:56
  • The correct formulation should be: _Objects are not passed to methods; rather, references to objects are passed, but **the references themselves are passed by value**. When a method receives a reference to an object, the method can manipulate the object directly, but **the reference value cannot be changed to refer to a new object**._ See [this link](https://www.informit.com/articles/article.aspx?p=2731935&seqNum=18#:~:text=By%20default%2C%20C%23%20does%20not,themselves%20are%20passed%20by%20value.). – alelom Jan 10 '21 at 12:19
1

There is no way, other than 'unsafe' code, to reproduce this behavior in C#. The C++ ability to have a pointer remain fixed to another variable, even when the second variable's identity changes, is simply not available in most other languages.

This is not a special feature of strings or any other type. For example, at the end of the following C++ code, 'g' points to the updated 'f', which is set to 'SomeOtherFoo':

Foo f;
Foo *g = &f;
f = SomeOtherFoo();
//'g' points to the updated 'f'

In 'safe' C#, at the end of the following code, 'g' is still the original object, not the new one returned by 'SomeOtherFoo':

Foo f = new Foo();
Foo g = f;
f = SomeOtherFoo();
//'g' does not point to the updated 'f'
Dave Doknjas
  • 6,394
  • 1
  • 15
  • 28
0

The core of the problem is that strings are treated as value types (primitive) in C# but as a reference type in C++. So assigning a string to another variable will simple copy the value as Dr.Haimovitz wrote.

One way you could access the actual pointers for variables in C# is by writing "un-safe code". https://msdn.microsoft.com/en-us/library/aa288474(v=vs.71).aspx

Sal
  • 5,129
  • 5
  • 27
  • 53
  • I'm pretty sure this is wrong. I believe strings are reference types with value behaviors. http://stackoverflow.com/questions/636932/in-c-why-is-string-a-reference-type-that-behaves-like-a-value-type – Sharpiro Aug 03 '16 at 02:09
  • Corrected my answer above to be more accurate. – Sal Aug 03 '16 at 02:23