-1

I've been reading up on value- and reference types as well as the ref keyword, with special attention to this post: C# string reference type?. Jon Skeet's answer "The reference to the string is passed by value. There's a big difference between passing a reference by value and passing an object by reference. It's unfortunate that the word "reference" is used in both cases." confuses me even after his example.

Consider this:

string x = "foo";

void Bar(string s)
{
    Console.Write(s);
}

Bar(x);

My question: when passing x to Bar, does s represent a full copy of x in memory or is s a pointer to x? This becomes relevant if x is really large. Would there be a performance benefit in passing x by ref when all I want to do is transform s into something different (without changing s itself?)

Rno
  • 784
  • 1
  • 6
  • 16
  • What it is passed is a copy of the reference of `x`. BTW transforming `string`s will always result in new `string`s. – dcg Dec 24 '19 at 01:13
  • Your code as written does not create multiple copies of the string at any point. You don't need to pass it by `ref`. – Blorgbeard Dec 24 '19 at 01:16
  • `s` is not a pointer to `x`, either. `x` is a reference to "foo". `s` is a copy of that reference, pointing to the same "foo". – Blorgbeard Dec 24 '19 at 01:18
  • Tx for the feedback. Is it then analogous to a **pointer in C? – Rno Dec 24 '19 at 01:20
  • I'd say it's just analogous to a *pointer. The only special thing about `string` is that it's "immutable" (the class just doesn't expose any mutation API). Passing around a `string` is just like passing any other `class` object. If you passed a `Dictionary` to a function, you wouldn't expect a copy to be made. You're basically passing a copy of a pointer. – Blorgbeard Dec 24 '19 at 01:27

3 Answers3

1

All string's in c# are immutable, so that is it safe to pass pointers around. In your example "foo" is a static constant that will exist somewhere in your assembly, and be loaded into memory into a fixed location. You are declaring x and assigning that location. Then passing that pointer into Bar, where a new local variable s is also assigned that value.

If Bar changed the value of s, it won't change the current value of x, since both variables are copies of the pointer location.

If Bar was changed to take s as a reference parameter, then s is no longer a separate local variable. Instead the location of x itself would be passed into Bar, and any changes to s and x would change the same pointer. The variable s becomes a reference to a variable that points to a string.

Jeremy Lakeman
  • 9,515
  • 25
  • 29
  • What I take from that is that we're talking pointers here, not copies (values) being passed around, right? – Rno Dec 24 '19 at 01:22
  • Class types are always allocated on the heap. Class variables are always pointers. Value types are stored within the scope they appear, local variables on the stack, class fields within their containing class. – Jeremy Lakeman Dec 24 '19 at 01:28
1

When passing x to Bar, does s represent a full copy of x in memory or is s a pointer to x?

Both x and s are variables which reference the same String object in memory - "Foo".

Would there be a performance benefit in passing x by ref when all I want to do is transform s into something different (without changing s itself?)

Passing the s parameter using the ref keyword allows you to assign the x variable to a different String object in memory (or null) by assigning a new String (or null) to the s parameter. But there is no performance difference because, in both cases, only an address is copied (either the address of the String "Foo" or the address of the variable x, respectively) - the contents of the String "Foo" is not copied.

andrew
  • 1,723
  • 2
  • 12
  • 24
  • 1
    thank you, as others pointed out it points to an address, which is what I wanted to know. – Rno Dec 24 '19 at 01:49
1

“when passing x to Bar, does s represent a full copy of x in memory or is s a pointer to x”.

x is a reference to “foo” not the full copy of “foo”.

When you do

Bar(x)

x is being passed by value (i.e. a copy of x is being passed not x itself) so anything you do in Bar will not change what x refers to. If you want Bar to change what x refers to then you must pass it by reference using the ref keyword. This would require change in Bar’s signature as follows:

void Bar(ref string s) { }

Then you can call it as:

Bar(ref x)

Passing by reference in this case has nothing to do with

performance benefits

but rather about achieving what’s desired (i.e. change what x refers to).

NGambit
  • 1,141
  • 13
  • 27
  • What confuses me is your 'a copy of x is being passed not x itself.' That suggests a copy, not a pointer as others 'pointed' out. – Rno Dec 24 '19 at 01:53
  • It’s a copy of the reference (i.e. copy of x) that’s being passed not the copy of “foo”. x is not the same as “foo”, it points to “foo” (I don’t like to use the word pointer here as it has baggage from C/C++) – NGambit Dec 24 '19 at 01:55