4

I understand that ref means the reference submitted may point to an entirely different object when the method returns.

However what I like about the ref modifier is that the developer immediately knows what he put in may be somehow different by the time the method returns, as the ref modifier is also required caller side.

Taking a simple method, from a hypothetical ORM:

public Boolean AddItem(Entity someEntity)
{
  try
  {
    // Add item to database
    // Get Id of entity back from database
    someEntity.Id = *returnedId*;
    return true;
  }
  catch (DBException ex)
  {
    return false;
  }
}

Any caller of the method may not know that their entity was updated by calling the method. However making someEntity a ref parameter, it indicates to the developer that their submitted parameter will be different, they then know to dig into the documentation/code to find out how it is changed, without the modifier they may have never thought to do so.

I know this is slightly abusing the ref modifier, as it is not actually required in the example above, but will using it this way actually cause me any problems?

Lee
  • 1,591
  • 1
  • 14
  • 28
  • 1
    By declaring members public you are deciding they can be accessed and/or modified by any external object that has a reference to your object. If it shouldn't be modified it should be private – Tobsey Apr 09 '15 at 08:56
  • I believe if `AddItem` author want to tell caller `Hey, I won't be modiyfing the paremeter`, he wil use a struct as parameter. In C++ there is `const` modifier that ensures that parameter will not be modified. Why it is not available in c#? Here is greate explanation: http://stackoverflow.com/questions/3263001/why-const-parameters-are-not-allowed-in-c-sharp –  Apr 09 '15 at 08:57
  • @Tobsey: There is a difference between "should be modifiable" and "should be modified within this method it is passed to". The OP is trying to somehow replicate something similar as C++'s `const` parameters. – O. R. Mapper Apr 09 '15 at 08:57
  • 3
    @ArtyomNeustroev There is no code to review here. OP is asking about a concept. Also, we don't review hypothetical code. Do not pass go. Do not collect $200. – Dan Apr 09 '15 at 08:59
  • Well, if the modification to the object passed in is that important, shouldn't this thing be reflected by the name of the method? And if it is just a complicated and important side-effect, perhaps the method deserves refactoring? – michaelb Apr 09 '15 at 08:59
  • 5
    I think this is a terrible idea. Now after calling such methods I need to check if my non-null reference has suddenly become null. The right approach to this issue is to use immutable types and/or correct method documentation, IMO. – Matthew Watson Apr 09 '15 at 09:02
  • @Lee please see http://stackoverflow.com/questions/3539252/when-is-using-the-c-sharp-ref-keyword-ever-a-good-idea. `ref`/`out` are widely regarded as "don't touch unless you know why you're touching it". I think it's safe to say this is not one of those cases – Dan Apr 09 '15 at 09:03
  • NO, no, no, no, nononoNO! Bad developer. Naughty! This just saying I might have put an awful side effect in the method and you should deal with it because I couldn't be arsed. – Tony Hopkinson Apr 09 '15 at 09:12
  • I hope `Entity` is a `class`, not a `struct`? – Jeppe Stig Nielsen Apr 09 '15 at 09:24
  • @pwas - No it should definitely not be a struct, entities are forever modified and do not represent a single unchanged value. – Lee Apr 09 '15 at 09:50
  • @michaelb - After looking at the answers, I think this is the only viable option. In this example it would be "AddItemAndUpdateIdValue", can you imagine how horrid a more complicated method could be come, which is why most people don't bother and you're left being surprised with extra functionality. I guess this is just something one has to live with! – Lee Apr 09 '15 at 09:52
  • @MatthewWatson - Valid point. But as a counter argument, as I don't know what parameters are pure inputs, and what parameters are inputs + can be changed, do I need to check everything? Question everything? I was hoping for a way to go "look here, stuff happens to this parameter" without having to resort to documentation or comments, but from the answers it looks like that's the only option. – Lee Apr 09 '15 at 09:54

2 Answers2

6

I think it is abuse. Assuming Entity is a reference type, the parameter declaration

bool AddItem(ref Entity someEntity)

indicates that the method might move the reference someEntity to "point to" an entirely different object instance.

If all you do is mutate the existing instance someEntity, do not write ref. Instead, use names (method name and parameter name) and documentation that make it clear you will "mutate" (change) the object. Example name (you can choose better names since you know the actual code): AddItemAndUpdateEntityID

Consequences of using ref:

  • the caller must use a variable. He cannot use the return value from a property, method call or expression evaluation
  • the caller must use the exact type, he cannot pass a SpecificEntity, say, where SpecificEntity derives from Entity
  • the logic of your method must be prepared that other threads (or other methods you call yourself) may change the identity of the ref parameter. For example, if you check if someEntity == null in the top of your method, at a later point in your method that might have changed because someone else might have moved the reference to point elsewhere.
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • I wasn't aware of those consequences, brilliant, just the answer I was looking for. Naming/comments it is! – Lee Apr 09 '15 at 10:02
4

However what I like about the ref modifier is that the developer immediately knows what he put in may be somehow different by the time the method returns

No they don't.

What they know about the ref modifier is that the parameter may actually refer to something else when the method returns.

Changing a method that accepts a reference type to use ref solely so that you can give a false impression is not useful in any way.

Of course there's also the flip side; as well as abusing ref to indicate something it doesn't mean, you've lost the ability of ref to indicate what it does mean; one would have to examine the code to see if the method was actually using ref and wouldn't otherwise know from one method call to another whether you were still dealing with the same object.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • I guess that could be confusing to someone who isn't familiar with the unconventional coding style, thanks for your answer. – Lee Apr 09 '15 at 10:00
  • 1
    It would be confusing to someone who is familiar with it; they'll still never know whether a method is really using `ref` or not. – Jon Hanna Apr 09 '15 at 10:14
  • Agreed, I very rarely (if ever?) find a reason to use ref for the functionality it actually provides, it seems to go to waste! Even if everyone were made familiar though, and told to look in comments for correct usages of ref (madness, I know), for the reasons Jepp explained it's not a viable option, and will be sticking to naming/comments. – Lee Apr 09 '15 at 10:22
  • I should hope you rarely use finalisers, or explicit garbage collection, or `stackalloc` or a lot of other things that are very useful when needed, but only rarely so needed. – Jon Hanna Apr 10 '15 at 11:48