Setting the Scene

By looking at the following two methods, arguably they seem to do the same thing. But they must be doing something different, hence there existence. So let’s find out.

What is passing by reference?

In C# method arguments are either passed by value or by reference. By value means passing a copy of the value type (no boxing is incurred) or a reference (pointer) in the case of reference type. In C# passing by parameter is achieved by ref/out modifiers.

 

Concerns

  1. Method Honesty. Method signatures having out parameters are usually a sign that you want to return more than one thing. In other words, the method becomes less honest; because it returns void and the out parameter. Also, the future of a method with an out parameter is more concerning (software is built to change). With every line of code we write we tend to set ourselves a pattern to follow for future changes. So if you had to extend that method signature you would probably choose to add an extra out parameter, as it is the least resistance path during development. Eventually, your method’s honesty is getting less and less as more parameters are returned.
  2. Leaks Abstraction. A caller method that has declared a local variable to be passed by reference, it requires uncovering the lid on the called method in order to understand how another method could affect the state of its local variable. In other words you are giving more power to the called method to manipulate the parameter.
  3. Side Effects. There is a difference between a value type and a reference type passed by reference in terms of side effects. With side effects managing the state of an object gets harder. In addition, the severity of the side effects vary but are still undesired effects. So what could happen to a reference type parameter passed by reference:
    1. No changes to the passed parameter, hence not being honest – Low severity
    2. Contents of the reference type changed. This is true always for any reference type – High Severity
    3. Enables the called method not to allocate a new object. This only happens if passed by reference – High Severity
  4. Thread Safety. A method (instance or static) is said to be thread safe only if it references variables scoped within that method stack (exception: the no lock deadlock). Imagine you have multiple threads calling a GetOutSomething(out paramByRef), and each thread is passing the same parameter by reference, then that is not thread safe, hence it is harder to handle concurrency. On the other hand, if multiple threads called a method, each one passing in its own variable by reference, then that makes it thread safe. Below example depicts this concern:
  5. Harder to Debug. Extra effort to debug variable passed by reference is obvious from points 3 and 4 above; inevitable complexity.
  6. Performance. Generally speaking passing by reference is slower, and more accurately it depends whether its value or reference types. Mainly value types are the ones that benefit from not passing by reference, it depends on the context i.e. passing a large struct by ref could save CPU cycles, but do it after you benchmark it.

    UntitledThe first two approaches which pass by ref perform relatively close, however the winner is the third approach the one that does not pass by reference.(Note: I run the above code 5 times for each approach in order to eliminate any cold start effects in a release build. Also did replace ref with out and performed almost similarly)
  7. Prevents Method Chaining. Method chaining syntax is becoming more popular in OO with adopted functional programming principles as in LINQ. VS compiler will complain of the following code with an error CS0023 (Roslyn Compiler)
  8. chaining_out_errorHarder to unit test. More effort is needed to mock out parameters compared to return values.
  9. Cleaner code. Although this is a matter of taste, but I think it is slightly related to point 1; honesty. Calling a method might enforce you create unused local variables just to comply with the method signature. For instance, the below code.
  10. Object orientation is built on a key concept which is objects, and objects are about encapsulating (code/data) hence wrapping the multiple out parameters in a single object seems more natural. But if the method only has one out parameter? Is it worth wrapping it? Maybe no if you are happy with all the concerns mentioned above.

Less of a Concern

We live in world where one size fits all is nonsense. Everything has purpose, and our job is to define it. So what is the purpose of out modifier? Why Microsoft introduced it in first place?

If you try to optimise for performance then passing by reference, in certain scenarios, as in C# API static methods (thread safe) TryParse or TryGetValue, is understandable. Because newing up a wrapper object with a bool and a result comes with price.

Summary

  • Use it sparingly; everything has purpose, and our job is to define it. A sensible purpose is if you want to return bool and a result as in system API
  • If you have to deal API of 3rd party libraries that return objects by reference then wrap out parameters to your domain object at the domain boundaries; the point where external code enters your domain.
  • If you are concerned about performance, then my advice is make you decision after you get the benchmark numbers first.
  • For efficiency reasons; avoiding instantiating a wrapper object of a bool and the result
  • If you are lazy to create a wrapper object/struct, then I am fine with Tuple
  • Whichever way you look at it, passing by reference leaks abstraction, because you give the called method extra permissions to manipulate parameters

Leave a Reply

Your e-mail address will not be published. Required fields are marked *