A MS help page about the difference between pass-by-value and pass-by-reference seems quite clear to me:
http://msdn.microsoft.com/en-us/library/8b0bdca4.aspx
However, a user comment at the end has confused me somewhat. It says (among other things) this:
if you don‘t use the ref or out keywords, then arguments to methods
are passed by value.
The comment seems quite wrong to me. Is it?
(I posted part of the comment out of context: Here's the full comment:)
The text says: "... but when a class instance is passed, a reference
is passed. ..." This is incorrect, as you can see in:
C# Language specification Version 4.0 (a Microsoft free download)
5.1.4 Value parameters A parameter declared without a ref or out
modifier is a value parameter.
So, in the example above, the class instance is passed by value, and
not by reference.
It is the full comment which is really confusing me... The class instance is passed by value and not by reference? Does that not imply that the instance bytes are pushed onto the stack?
The comment is true. Without ref or out, the variable is passed by value. However, with objects, what you are passing by value is a reference.
The only time you would want to pass an object-reference by reference is if you are assigning a new object to the parameter within the method and you want that reassignment to affect the caller's copy of the reference.
You aren't ever really passing an object around. Instead you are passing around references to an object. With that in mind, this byval/byref business applies to the object-reference, not the object itself.
Jon Skeet has a great post about this topic.
The complete comment is misleading. The object's reference is passed by value.
The comment is completely correct. The confusion here is that value types and reference types are pretty much unrelated to passing an argument by value or by reference.
When you pass a value type as a non-ref parameter, you pass its value. That's clear enough. For a reference type, though, you are still only passing a value: You are passing the value of the reference itself.
If the parameter is ref/out, though, then you are actually saying that the parameter is an alias for the variable that is actually being passed in. In that case, it doesn't matter if it's a value type or a reference type; a reference to the variable is being passed, not just a value.
Related
I'm learning C# with Yellow Book. In the chapter 3.1.9, when describing differences between passing parameter values as ref vs out, it says the following:
When you pass a parameter as a reference you are giving the method complete control of it. Sometimes you don't want this. Instead you want to just allow the method to change the variable.
If I am the one coding the method, i.e. its behavior, how am I giving it complete control of it?
It doesn't mean it is less secure, it just means the method "has control over your variable" that you are passing as parameter for "processing". It can potentially return a completely new object and not the one you "provided". More can be found here:
When used in a method's parameter list, the ref keyword indicates that an argument is passed by reference, not by value. The ref keyword makes the formal parameter an alias for the argument, which must be a variable. In other words, any operation on the parameter is made on the argument.
For example, suppose the caller passes a local variable. The called method can then replace the object to which the ref parameter refers. In that case, the caller's local variable or the array element refers to the new object when the method returns.
Are BigIntegers in C# passed by value or by reference? I am having a code in which I need to pass them by value and I think they are passed as reference personally, as the value is changed after some calls in initial calling function, not sure though if it is the case actually.
Please help :)
Technically speaking, all objects in C# (and Java as well) are passed by value (by default).
For reference types, this value happens to be a reference (pointer). That's why changes inside the method affects the actual object.
For value types, this value is the actual value the variable holds. That's why changes inside the method doesn't affect the actual object.
BigInteger is not special in anyway, it's a struct (which is a value type).
If you want to pass an object by reference, you can use ref keyword.
See also:
Passing Reference-Type Parameters (C# Programming Guide)
Passing Value-Type Parameters (C# Programming Guide)
You may also want to give a look at the answers for this question.
BigInteger is a struct, so it is a value type and it is passed by value by default:
Because a struct is a value type, when you pass a struct by value to a method, the method receives and operates on a copy of the struct argument. The method has no access to the original struct in the calling method and therefore can't change it in any way. The method can change only the copy.
Passing Value-Type Parameters (C# Programming Guide)
A value-type variable contains its data directly as opposed to a reference-type variable, which contains a reference to its data. Passing a value-type variable to a method by value means passing a copy of the variable to the method. Any changes to the parameter that take place inside the method have no effect on the original data stored in the argument variable. If you want the called method to change the value of the argument, you must pass it by reference, using the ref or out keyword. You may also use the in keyword to pass a value parameter by reference to avoid the copy while guaranteeing that the value will not be changed. For simplicity, the following examples use ref.
If you want to pass such type by reference, you can use the ref keyword.
Passing Reference-Type Parameters (C# Programming Guide)
A variable of a reference type does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data belonging to the referenced object, such as the value of a class member. However, you cannot change the value of the reference itself; for example, you cannot use the same reference to allocate memory for a new object and have it persist outside the method. To do that, pass the parameter using the ref or out keyword. For simplicity, the following examples use ref.
It will therefore be only the memory pointer (4 or 8 bytes on x32 or x64 systems) which is pushed into the stack before the call of a method (like an instance of a class) instead of the entire structure content (the copy of all members, for example 8x4 bytes if the struct has 8 integers, at least).
Pass c# struct by reference
Passing a struct by Reference
Pass reference by reference vs pass reference by value - C#
Passing a Reference vs. Value (Pluralsight)
Understanding C# Pass by Reference and Pass by Value (Udemy)
Passing Arguments By Value and By Reference (C# 6 for Programmers, 6th Edition)
There are many examples, let's take array copy method as an example. The signature of the Array.Copy is method is as below
public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length);
Judging only from signature, one can not tell that the sourceArray will not be changed while the destinationArray will be altered, even if it is some thing as simple as an array of Int. The guarantee coming from the keyword "ref" for programmers have lost here.
It seems to me that the the destinationArray parameter should better be marked as "ref Array". If it had been done this way, the syntax would be more consistent with the usage of the keyword "ref", indicating that the passed in object might be modified by the callee and the change is visible for the caller. The only benefit I can think of concerning mitting the keyword "ref", is that saves a few key strokes. or it is just mimicking the C/C++ style without much thinking.
My question is: what are some seasonings behind this design decision?
Update: For the record, I am advocating that an array be of the same value/reference category as its elements, thus making a clear extinction between Fun(array) and Fun(ref array), that is the same guarantee programmers get with Fun(int) and Fun(ref int). Optimization for efficiency can be left to the implementation level.
Array is a reference type. You can pass references by value and the instances they reference will still be the same ones that get modified. The callee is modifying the same instance using its own reference to it and has no reason to change it into a completely different instance entirely (which is where ref would actually come into use).
There isn't any convention that states to use ref when passing reference types — you generally don't need to most of the time, except as mentioned if your method actually intends to change the instance entirely like so:
class Foo { public int Value; }
public static void ReplaceFoo(ref Foo foo)
{
foo = new Foo { Value = 2 };
}
var foo = new Foo { Value = 1 };
Console.WriteLine(foo.Value);
ReplaceFoo(ref foo);
Console.WriteLine(foo.Value);
Judging only from signature, one can not tell that the sourceArray will not be changed while the destinationArray will be altered
Why is this a problem? No one reads APIs only paying attention to method signatures and ignoring parameter names. Signatures are there for the compiler to distinguish overloads. Anyone reading the API for Array.Copy() would understand that sourceArray is going to be unchanged, being where the method is getting the values from, and destinationArray is going to be modified, being the one receiving the values — unless they don't speak English (which is fine, but most APIs are written in English).
The only other scenario I can think of where a reader would be confused is if they didn't have the prior knowledge that arrays are reference types in .NET. But misusing ref in a situation where it's not needed at best and inappropriate at worst doesn't solve that problem.
C# (and .NET) include both reference types and value types.
Normally (absent ref or out keywords), parameters are passed to methods by value. So, if you pass an integer to a function, the value of the integer is passed. If you put a a variable referring to an array in a function call (remembering that all arrays are instances of the reference type System.Array), the value of that variable, i.e., the reference to to the array, is passed to the function.
So, within the function, the code gets to play on that array. When the function returns, that variable (in the scope of the caller) still refers to that same object. However, the function may have mutated that array, so the variable (in the caller scope) may be referring to a changed object.
If you pass a value type by reference (with the ref keyword), the function can change the value of the parameter, and when the function returns, the variable (in the caller scope) will receive the new value.
But, if you use ref (or out) on a parameter of reference type, you are passing a reference by reference. So, for example, you could pass in an array of five integers and the function could assign that parameter and array of ten integers (they are of the same type, but definitely differentobjects). In the caller, when the function returns, the variable associated with that parameter will see what it refers to completely change during the call.
In your example, the caller will instantiate two arrays of the same type and compatible lengths (usually the same length if the source and destination indexes are 0 and the length is sourceArray.Length). The function does not change what object the destination array parameter refers to, it just fills the destination from the source.
In fact, if the destination was by ref, it wouldn't be as flexible. Consider a case where the destination is 30 entries long, and your intention is to fill the middle ten array entries with the source. It just works. It wouldn't with a ref destination parameter (without a lot more work).
The reason for omitting the ref keyword is that in most cases, it won't make any difference to include it, so it's superfluous. However, it does actually make a difference in some cases. An array is a reference type, and that means a value representing that reference gets passed. Normally, updating the passed in value will trigger updates to the original object. BUT if you create a NEW array and assign the passed in parameter to the new item, the reference gets lost - whereas the ref keyword preserves it.
I was recently reading an answer about CS1628, "Cannot use ref or out parameter 'parameter' inside an anonymous method, lambda expression, or query expression".
The answer stated a way around this is to implement "ref parameters as boxes" in the CLR.
C# compiler error CS1628 with VS2010/C#4
I am unsure what this means and seem to be unable to find any references to it in google.
Can anyone please explain this to me as its way over my head?
You can declare a "box" class:
class Box<T> { public T Value; }
Pass an instance of that class to the method that you cannot use ref with. The method can reach into the object and mutate Value. The caller can later extract Value.
This works (in constrast to ref) because Box is allocated on the heap and has "infinite" lifetime. ref can only refer to locations with more restricted lifetime.
After reading the MSDN article on the ref keyword, I am confused as to what C# does when you pass a value type using the ref keyword. The documentation states that the ValueTypes are not boxed. My question is how does C# handle passing a value type as a reference? Is it passing some copy to the data that is allocated on the Stack? Thanks.
Is it passing some copy to the data that is allocated on the Stack?
No, it does not make a copy. ref and out keyword can be compared to passing by pointer in C or passing by reference in C++, when the memory location (i.e. an address) of the variable is passed to the target method. The method that takes a reference would then modify the value directly in place using the memory location passed in.
Knowing that the variable is passed by reference, compiler inserts instructions that treat the ref variable as an address, allowing in-place modifications.
tl;dr: Boxing isn't "how you create a reference"; it's "how you package a primitive value type for consumers who don't expect that exact type".
In .NET, reference types are class instances on the heap. Value types like int or double are just the bytes: A 32-bit int is just four bytes worth of zeroes and ones. When you put it in, say a System.List (the old-timey pre-generic kind, that Granpaw whittled out down at the General Store), then take it back out, how will the compiler know what to do if you call GetType() on it? It would just have four bytes of... what? Who knows? If it stored a pointer in the List, it would have a pointer to four bytes of... who knows?
In your own method, the generated code knows what your variable is. Regular strong type-checking. But that doesn't work when you send your variable's value it to somebody else who only knows he's expecting Object.
So when you add an int to a List, or pass it to a function that takes Object as an argument, the compiler has to add some information to it so everybody else knows what he's getting.
So "Boxing" means packaging a non-reference value into an object that can be treated as an instance of Object. For ordinary ref parameters, that's not necessary, because the type is known the whole way: The code generated for the guts of the function doesn't have to be prepared to deal with any arbitrary reference type. It knows it's getting (for example) a pointer to an integer, and that's all it's going to get. Boxing provides capability that's not required in this case, and so the compiler doesn't waste your users' cycles on it.
Boxing isn't the only way to have a reference (in the broadest sense of the term) to, for example, a double. Rather, boxing is the only way to treat a double as an object that can be stored in a System.List: It has to be on the heap, it has to be castable to Object, has to have run-time type information, etc. etc.
For the following, all all the caller or the callee need is the address of 64 zeroes and ones somewhere:
void f(ref double d) { d *= 2; }