18

What are the things to consider when choosing between ByRef and ByVal.

I understand the difference between the two but I don't fully understand if ByRef saves resources or if we even need to worry about that in the .Net environment.

How do you decide between the two if the functionality doesn't matter in a situation?

Kevin Fairchild
  • 10,891
  • 6
  • 33
  • 52
ctrlShiftBryan
  • 27,092
  • 26
  • 73
  • 78
  • I'm not sure I asked the question properly. Is there a .Net equivalent to passing something ByRef as ReadOnly(As you would in Java)? To save resources? – ctrlShiftBryan Nov 14 '08 at 15:32
  • 1
    Please show the Java syntax, and we'll say whether or not you could do the same in C#. Bear in mind that Java is purely pass-by-value... – Jon Skeet Nov 14 '08 at 15:39
  • In other languages in order to save resources large objects can be passed by read only reference in order to save resources. It acts like a passed by value reference but does not make a copy. – ctrlShiftBryan Nov 14 '08 at 15:48
  • Yes, but there's nothing like that in Java... that's why I asked for a Java example. – Jon Skeet Nov 14 '08 at 17:15

10 Answers10

35

There's a lot of misinformation around about this. The main thing is that you understand the difference between value types and reference types, and the difference between pass by value and pass by reference.

You almost always want to pass by value. Passing by reference is almost always for "I want to return more than one result, and not just by adding things to a list which is passed in." The classic example of a method using pass-by-reference is Int32.TryParse where the return value is a success/failure, and the parsed value is "returned" by an out parameter.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 4
    +1. Passing by ref and changing inside a method that returns void is a common 'mistake' in my mind - it's misleading as to what the method is doing. – Kon Nov 14 '08 at 15:04
  • 5
    Many developers are still prone to use this pattern - maybe because their background is from C++, or in COM, where ret vals were always error codes and this pattern was necessary ? – Charles Bretana Nov 14 '08 at 15:25
15

The default is byValue for ALL types, but it is important to understand what the two options mean for a "reference type" (a class) as opposed to a value type. (structs).

For a reference type, if you declare a reference type variable in a method, that variable is a memory location in the stack frame of the method. It is not on the heap. When you initialize that variable (using new or a factory, whatever), then you have created an actual object on the heap, and the address of that object is stored in the declared reference variable in your methods stack frame.

When you pass a reference type to another method byVal, you are creating a copy of the address stored in the calling methods stack and passing the copy of that value (the pointer address) to the called method, where it is stored in a new memory slot in the called methods stack. Inside the called method, the new cloned variable points directly to the same object on the Heap. So using it can change the properties of the same object. But you cannot change which heap object the original reference variable (on the calling methods stack) points to. If, in the called method I write

  myVar = new object();

The original variable in the calling method will not have changed to point to a new object.

If I pass a reference type byRef, otoh, I am passing a pointer to the declared variable in the calling methods stack (which contains a pointer to the object on the heap) It is therefore a pointer to a pointer to the object. It points to the memory location on the calling methods stack, which points to the object on the heap.
So now, if I change the value of the variable in the called method, by setting it to a new object(), as above, since it is a "refereence" to the variable in the calling method, I am actually changing which object the variable in the calling method is pointing to. So After the called method returns, the variable in the calling method will no longer be pointing to the same original object on the heap.

Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • This is certainly what I've learned in the Java world but I'm not sure it is so in .Net? – ctrlShiftBryan Nov 14 '08 at 14:48
  • I'm not a Java guy, but I had heard that Java did not even have value types.. That every variable was a reference type... Is that wrong? – Charles Bretana Nov 14 '08 at 14:50
  • 1
    Yes, it's wrong. Java has value types. What it doesn't have is user-defined value types. – Jon Skeet Nov 14 '08 at 15:08
  • ahh, so, you mean things like int, short, ulong, decimal, char, etc... are implemented as value types, on each methods stack frame, but any custom user defined type is implemented as ref type on heap ? – Charles Bretana Nov 14 '08 at 15:22
  • Yes, although bear in mind that value types end up on the heap as part of other objects too. See http://pobox.com/~skeet/csharp/memory.html – Jon Skeet Nov 14 '08 at 15:39
  • yes, what we call a "field" in .Net... a variable declared within a type (class or struct) which is outside of any method, property or constructor... – Charles Bretana Nov 14 '08 at 15:46
  • +1 because the answer is pretty damn relevant considering how the question was asked (and correct) -- however, I think the asker wanted to specifically know about value types in .NET. – BrainSlugs83 Mar 01 '12 at 06:27
  • 1
    FYI, in Java, yes there are value types for things like int, short, double, etc... there are also class types like Integer, Double, etc... in .NET int is just an alias for Int32, it's a value type with methods, etc... in Java, they are not the same at all; Integer is a class which wraps an int which gives it properties (you pass an int into the constructor even). In .NET you can go so far as to say 42.ToString() -- try doing that in Java. – BrainSlugs83 Mar 01 '12 at 06:30
  • The value for a reference type being on the stack or the heap is irrelevant. It's an implementation detail that could be changed at any time. What is relevant is that another reference is created to the same object and it's place in memory (wherever that may be), i.e. a copy of the REFERENCE is what gets passed. For structures, a copy of the OBJECT is passed. – jmoreno Feb 13 '17 at 15:23
8

ByVal should be your "default". Use it unless you have a specific reason to use ByRef

Kevin
  • 7,162
  • 11
  • 46
  • 70
  • [According to Microsoft](http://msdn.microsoft.com/en-us/library/ddck1z30%28v=vs.120%29.aspx): **The default in Visual Basic is to pass arguments by value.** And for this reason, the recommended practice is generally to omit the `ByVal` keyword. See [this answer](http://stackoverflow.com/a/9207733/1497596) for more. – DavidRR Jan 01 '14 at 22:19
  • Here's a confusing contradiction to that article that says the default is ByRef but that the argument will be passed Reference or value, depending on other factors. [link](https://msdn.microsoft.com/en-us/library/ddck1z30(v=vs.120).aspx) – Sudsy Dec 04 '15 at 19:30
  • I think it is a weird way of trying to avoid having to go into the detail about the difference between [value and reference types](https://msdn.microsoft.com/en-us/library/aa711899(v=vs.71).aspx). – Sudsy Dec 04 '15 at 19:40
8

Passing an object ByVal in .net does not make a copy of the object and does not consume more resources then ByRef, A pointer is still passed through to the function. The runtime just ensures that you can't modify the pointer in your function and return a different value for it. You can still make changes to the values within the object and you will see those changes outside the function. That is why ByRef is uses so rarely. It is only needed when you want a function to change the actual object that is coming back; hence an output parameter.

DancesWithBamboo
  • 4,176
  • 1
  • 19
  • 20
  • Is this true? Why did it get voted down? Maybe I didn't ask the question properly because this is more along the line of the answer I was looking for. – ctrlShiftBryan Nov 14 '08 at 14:49
  • 4
    It is technically true, but very misleading. When passing an object byVal, the "object" is not copied, but the object's address IS copied, and passed to the called method. When passing byRef, the object's address is NOT copied, the address of the addesss is passed. – Charles Bretana Nov 14 '08 at 15:39
  • This is not true, even for classes, technically. But for value types it's even more not true. -- For classes you pass a COPY of a POINTER to the class when passing byval. Again, that pointer is COPIED. (Hence if you reassign the pointer in the callee, the caller will not pickup the change.) For value types, if you pass by value, since there is no pointer, a COMPLETE copy is made; For instance if you pass a 200-byte struct byval, 200 bytes is copied for each call -- versus, byref only a 4 (or 8, depending on architecture) byte POINTER is copied. – BrainSlugs83 Mar 01 '12 at 07:16
5

Use "ByRef" only if the parameter is "output" parameter. Otherwise use "ByVal". Using "ByRef" on parameters which explicitly should not return values is dangerous and can easy generate bugs.

TcKs
  • 25,849
  • 11
  • 66
  • 104
  • 3
    No. Use "Out" if the parameter is to be an "output" parameter. Use "ByRef" if the parameter is to be a "Reference" parameter. – BrainSlugs83 Mar 01 '12 at 07:10
3

I would argue that ByRef should never be used--that it's a bad practice. I would apply that even to its typical use case of allowing a function to return multiple values (via ByRef parameters). It would be better for the function to return a structured response that includes those multiple return values. It's more clear and more obvious if a function only returns values via its return statement.

Mario
  • 6,572
  • 3
  • 42
  • 74
  • Yup, entirely correct. Its inclusion in .NET was a major brainf*ck. – Konrad Rudolph Jul 07 '11 at 16:50
  • I disagree. It can be extremely useful for things like the classic swap method: "Swap(ref T a, ref T b) where T: struct { ... }" (apologies if I got the syntax wrong) – BrainSlugs83 Mar 01 '12 at 07:22
  • How would one use `Threading.Interlocked.Increment` and other such members without `ByRef`? – supercat Jun 27 '12 at 22:53
  • 1
    It is exactly what you need when you need it. Most of the time however you don't. So should only be used when you specifically need it. – DarcyThomas Oct 10 '12 at 05:20
  • 1
    Totally agree, a function with ByRef is a very bad practice. And it is pretty weird especially for those coming from Functional programming background. – N.T.C Aug 18 '14 at 11:51
  • A design decision determines whether you need to use ByRef. I've been programming in .NET since it's inception and I have never made a decision that's caused me to need it. – Mario Sep 24 '14 at 13:11
  • Would you consider using ByRef when supplying params for a function calling a db that returns the number of records found? The records you receive back are in the ByRef param. – Luminous Oct 01 '14 at 18:26
0

According to Microsoft, choosing ByVal or ByRef can affect performance for large enough values (see Passing Arguments by Value and by Reference (Visual Basic)):

Performance. Although the passing mechanism can affect the performance of your code, the difference is usually insignificant. One exception to this is a value type passed ByVal. In this case, Visual Basic copies the entire data contents of the argument. Therefore, for a large value type such as a structure, it can be more efficient to pass it ByRef.

[emphasis added].

oscar
  • 355
  • 1
  • 2
  • 13
0
Sub last_column_process()
Dim last_column As Integer

last_column = 234
MsgBox last_column

trying_byref x:=last_column
MsgBox last_column

trying_byval v:=last_column
MsgBox last_column

End Sub

Sub trying_byref(ByRef x)
x = 345
End Sub

Sub trying_byval(ByRef v)
v = 555
End Sub
Ashwith Ullal
  • 263
  • 3
  • 10
0

Marking certain arguments as ByRef shows the user of your function that the variable allocated to that argument **will be modified.****

If you use ByRef for all args, there'll be no way to tell which variables are modified by the function, and which are just read by it. (apart from peeking inside the function source!)

Robin Rodricks
  • 110,798
  • 141
  • 398
  • 607
0

Lots of confusion I will try to simplify. You basically have 4 choices:

  1. Pass a value type byVal
  2. Pass a value type byRef
  3. Pass an object byVal
  4. Pass an object byRef

Some people say you should never use byRef. While they are technically correct, one thing is for certain. You should NEVER use the word never. If you are designing a system from scratch then byRef should be avoided at all costs. Using it exposes a design flaw. However working on an existing system may not provide as much flexability to implement a good design. Sometimes you must make consessions, i.e. using byRef. For example if you can get a fix in done in 2 days using byRef then that can be preferable to re-inventing the wheel and taking a week to get the same fix in just to avoid using byRef.

Summary:

  1. Using byVal on a value type: Passes a value to a function. This is the preferred way to design functions.
  2. Using byRef on a value type: Useful for returning more than one value from a function. If you are creating a function that needs to return more than one value to an existing system this can be better than creating an object (and setting properties, and disposing) just for one function.
  3. Using byVal on an object: Passes a pointer of an object to a function. The function can modify the object.
  4. Using byRef on an object: Passes a pointer to a pointer of an object to a function. Allows changing the object the caller is pointing to. This can cause some hard to find bugs and I can not think of any good reason to use it. Doesnt mean there isnt one, but if there is they are few and far between.
Joe
  • 379
  • 1
  • 6
  • 21