views:

1130

answers:

7

I want to give a certain linked list to a class I am making. I want the class to write into that list (eg by .addLast()).

Should I use the ref keyword for that?

I am somewhat puzzled on where to use the ref and out keywords in C#, as all classes are allocated dynamically on the heap and we actually use pointers for most operations.
Of course, out and ref keywords make sense for primitives and structs.

Also, if I don't send the list directly, but send a class containing the list? (it's internal and needed), do I still need to use ref? or if I pass it between functions, ex:

void A(ref LinkedList<int> list){
    B(list);
}

void B(ref LinkedList<int> list){
    _myList = list;
}
A: 

No you don't need to use ref.

LinkedList is an object, so it is already a reference type. The parameter list is a reference to the LinkedList object.

See this MSDN article for a description of value types. Value types usually the parameters you would use the ref or out keywords with.

You may also want to pass reference types by ref. This will allow you to point the reference to another object.

Any time you pass an object o you are really passing a reference to the object. When you pass a `ref object o' you are passing a reference to the reference. This allows to you modify the reference.

Passing Reference-Type Parameters may also help you understand.

dss539
This is slightly misleading, as it implies that ref should only be used with non-references types (i.e. value types). It can in fact be used just as well with either, and commonly is!
Noldorin
This is actually more than slightly misleading. The "ref" keyword has nothing to do with whether it is a reference type. It is used for being able to change the reference that is passed in.
HVS
Thanks for the notes I'll try to clarify that in the text.
dss539
@HVS: Well, it depends how you interpreted the statement. It was pretty vague, so there's a lot of scope. I was probably being kind with the "slightly". Indeed, the use of `ref` and reference types is completely independent, as I explain in my answer.
Noldorin
Indeed, this is *extermely* misleading. "No you don't need to use ref. It's already a reference type." implies that the ref keyword does nothing when used with reference types and should never be used. This is a bad answer in my mind.
configurator
@configurator, that wasn't the intended meaning but I can see how you might interpret it that way.
dss539
+13  A: 

This is a common misconception of the use of ref keyword in C#. Its purpose is to pass either a value or a reference type by reference, and you only need it in specific circumstances where you need a direct reference to the actual argument, rather than a copy of the argument (be it a value or reference itself). It is imperative not to confuse reference types with passing by reference in any case.

Jon Skeet has written an excellent article about parameter passing in C#, which compares and constrats value types, reference types, passing by value, passing by reference (ref), and output parameters (out). I recommend you take some time to read through this in full and your understanding should become much clearer.

To quote the most important parts from that page:

Value parameters:

By default, parameters are value parameters. This means that a new storage location is created for the variable in the function member declaration, and it starts off with the value that you specify in the function member invocation. If you change that value, that doesn't alter any variables involved in the invocation

Reference parameters:

Reference parameters don't pass the values of the variables used in the function member invocation - they use the variables themselves. Rather than creating a new storage location for the variable in the function member declaration, the same storage location is used, so the value of the variable in the function member and the value of the reference parameter will always be the same. Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference. Let's look at our previous examples, just changing the parameter to be a reference parameter:

To conclude: having read my reply and Jon Skeet's article, I hope that you will then see that there is no need whatsoever for using the ref keyword in the context of your question.

Noldorin
the answer is good, but however it gave me the opposite impression. I am reading Jon Skeet's article now, thanks.
Nefzen
Gave you the opposite impression... what do you mean, and how so?
Noldorin
I had the impression that sending a class by value will call the copy constructor, because it is copied "by value". That made even less sense with no *need whatsoever* to use `ref`, so I got to the right answer in the end.
Nefzen
Passing a class by value *does* copy the value. The key here is that the "value" is actually a *reference to the object* -so you're really just creating a new reference that points to the same object (reference type) on the heap.
Noldorin
And don't worry, I would begrudge you for accepting the other answer! ;)
Noldorin
yes, now I understand. And the other answer was just clear and simple, so I chose that, though it seems it evened out with votes.
Nefzen
+5  A: 

For what you're doing you don't need to use ref. If you did pass the list using ref, you would be allowing the caller to change which list you're referencing, rather than just changing the contents of the list.

Jon B
oh, so the value copied is the reference and not something like .Clone(). This makes sense.
Nefzen
A: 

Jon Skeet's take on it explains it well.

Mark Simpson
+2  A: 

In the two snippets you posted there is no need to pass list by ref. To quote Jon Skeet, object references are passed by value. This means, you would want to ref a reference type when the method will or might change the object reference and you want this new reference to carry back to the calling method. For example:

void methodA(string test)
{
    test = "Hello World";
}

void methodB(ref string test)
{
    test = "Hello World";
}

void Runner()
{
    string first= "string";
    methodA(first);
    string second= "string";
    methodB(ref second);
    Console.WriteLine((first == second).ToString()); //this would print false
}
Timothy Carter
A: 

The only time you need to use ref with a reference type is if you're going to be creating a new object inside a function.

Example #1: ref keyword not necessary.

// ...
   List myList = new List();
   PopulateList(myList);
// ...
void PopulateList(List AList)
{
   AList.Add("Hello");
   AList.Add("World");
}

Example #2: ref keyword necessary.

// ...
   List myList;
   PopulateList(myList);
// ...
void PopulateList(ref List AList)
{
   AList = new List();
   AList.Add("Hello");
   AList.Add("World");
}
Spencer Ruport
A: 

I am adding this answer for programmers that are used to C++ like myself.

Classes, interfaces, delegatess and arrays are reference types, meaning that they have an underlying pointer. Normal function calls copy this pointer(reference) by value, while sending by reference sends sends a reference to this reference:

//C# code:
void Foo(ClassA     input)
void Bar(ClassA ref input)

//equivalent C++ code:
void Foo(ClassA*  input)
void Bar(ClassA*& input)

Primitives such as int, double, etc structs and strings(string are an exception to these, but works similar), are allocated on the heap, so things work a bit different:

//C# code:
void Foo(StructA     input)
void Bar(StructA ref input)

//equivalent C++ code:
void Foo(StructA  input)
void Bar(StructA& input)

the ref keyword needs to be used both in declaration of the method and when calling it, so it would be clear it is referenced:

//C# code:
void Foobar(ClassB ref input)
...
ClassB instance = new ClassB();
Foobar(ref instance);

//equivalent C++ code:
void Foobar(ClassB*& input)
...
ClassB instance* = new ClassB();
Foobar(instance);

As said before, please read this detailed explanation. It also explains about strings.



It is interesting to note that calling by reference works with an underlying pointer, so we get to this code:

//C# code:
void Foo(ClassA input){
    input = input + 3;
}
void Bar(ClassA ref input){
    input = input + 3;
}
//equivalent C++ code:
void Foo(ClassA&  input){
    input = input + 3;
}
void Bar(ClassA*&  input){
    *input = *input + 3;
}
//equivalent pure C code:
void Fun(ClassA* input){
    *input = *input + 3;
}
void Fun(ClassA** input){
    *(*input) = *(*input) + 3;
}

it's a rough equivalent, but it's somewhat true.

Nefzen