6

When calling a method with a ref or out parameter, you have to specify the appropriate keyword when you call the method. I understand that from a style and code quality standpoint (as explained here for example), but I'm curious whether there is also a technical need for the keywords to be specified in the caller.

For example:

static void Main()
{
    int y = 0;
    Increment(ref y); // Is there any technical reason to include ref here?
}

static void Increment(ref int x)
{
    x++;
}
Community
  • 1
  • 1
Jason Watkins
  • 3,766
  • 1
  • 25
  • 39

4 Answers4

12

The only technical reason I could think of is overload resolution: you could have

static void Increment(ref int x)

and also

static void Increment(int x)

This is allowed; without ref in the call, the compiler wouldn't be able to tell them apart.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I was literally seconds away from posting this myself. – Snixtor Apr 19 '13 at 02:48
  • True enough, but can you provide an example where that overload is actually sane? I can't come up with one. – Jason Watkins Apr 19 '13 at 02:53
  • 3
    @JasonWatkins I can come up with a semi-sane one, when you make a communication library that could post a new value to the server in "post and forget" mode, or posts a new value, waits for a response, and writes the returned value back to the `ref` parameter. Personally, I would give the two different names, but since the semantics of the two are close enough, I could buy an argument that an overload is warranted. – Sergey Kalinichenko Apr 19 '13 at 03:03
  • 3
    @JasonWatkins: The language team doesn't care your "business scene". They considered ref/out keyword part of the method's signature, that's why you need it in the caller. – Cheng Chen Apr 19 '13 at 03:03
11

If you're asking whether the language could have been designed so that those aren't needed at the call site, the answer is yes. There is no particular reason they could not have been left out. The compiler has all the information it needs from the metadata, so it could make the proper transformation.

That said, doing so would have made it impossible to have these two overloads:

public void DoSomething(int x);
public void DoSomething(ref int x);

The compiler wouldn't be able to disambiguate that.

Although the ref and out could have been made optional, in which case those overloads would be allowed. And the compiler could either take the default (i.e. the non-ref), or issue an ambiguity error and make you specify which one you really wanted.

All that said, I like having to specify ref and out at the call site. It tells me that the parameter could potentially be modified. Having worked in Pascal for many years, where a var parameter is passed the same way that a value parameter is passed (the syntax at the call site is the same), I much prefer the specificity of C# in that regard.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • 1
    Thanks Jim. That's exactly what I'm asking. I just wanted to make sure that there wasn't something I was missing. As for the overload resolution, I'm not sure that disallowing that overload would be a bad thing! – Jason Watkins Apr 19 '13 at 02:50
  • 1
    Should probably mention that you cannot overload `DoSomething(ref int x)` with `DoSomething(out int x)` or vice versa. – Izzy Apr 23 '13 at 15:37
9

Another reason to require the modifier is to make changing a parameter to a ref or out a breaking change. If the ref/out could be inferred, then an evil programmer changing a parameter from by-value to by-reference would not be detected by clients compiling against the new signature. If a client called the method

public int Increment(int x)
{
    return x + 1;
}

by using

int result = Increment(x);

Suppose an evil developer decided to change the implementation to instead change the value passed by reference and return an error code if, say, the increment resulted in an overflow:

public int Increment(ref int x)
{
    x = x + 1;
    if(x == int.MinValue)  // overflow
        return -1;
    else 
        return 0;
}

Then a client building against the signature would not receive a compile error, but it would almost certainly break the calling app.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
-1

The compiler needs to know the method parameters it is interpreting when it is building IL. One reason is having overloads like:

public void (ref int x) {}
public void (int x)     {}

Another reason is out will explicitly allow you to use pass-by-value parameter use the interpreted value outside the method. ref will give the pointer to the parameter thereby pointing any new value from the method to the same memory location

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
ancoder
  • 81
  • 1
  • 5