Why doesn't C# support the return of references?
I have read that .NET supports return of references, but C# doesn't. Is there a special reason? Why I can't do something like:
static ref int Max(ref int x, ref int y)
{
if (x > y)
return ref x;
else
return ref y;
}
Solution 1:
This question was the subject of my blog on June 23rd 2011. Thanks for the great question!
The C# team is considering this for C# 7. See https://github.com/dotnet/roslyn/issues/5233 for details.
UPDATE: The feature made it in to C# 7!
You are correct; .NET does support methods that return managed references to variables. .NET also supports local variables that contain managed references to other variables. (Note however that .NET does not support fields or arrays that contain managed references to other variables because that overly complicates the garbage collection story. Also the "managed reference to variable" types are not convertible to object, and therefore may not be used as type arguments to generic types or methods.)
Commenter "RPM1984" for some reason asked for a citation for this fact. RPM1984 I encourage you to read the CLI specification Partition I Section 8.2.1.1, "Managed pointers and related types" for information about this feature of .NET.
It is entirely possible to create a version of C# which supports both these features. You could then do things like
static ref int Max(ref int x, ref int y)
{
if (x > y)
return ref x;
else
return ref y;
}
and then call it with
int a = 123;
int b = 456;
ref int c = ref Max(ref a, ref b);
c += 100;
Console.WriteLine(b); // 556!
I know empirically that it is possible to build a version of C# that supports these features because I have done so. Advanced programmers, particularly people porting unmanaged C++ code, often ask us for more C++-like ability to do things with references without having to get out the big hammer of actually using pointers and pinning memory all over the place. By using managed references you get these benefits without paying the cost of screwing up your garbage collection performance.
We have considered this feature, and actually implemented enough of it to show to other internal teams to get their feedback. However at this time based on our research we believe that the feature does not have broad enough appeal or compelling usage cases to make it into a real supported language feature. We have other higher priorities and a limited amount of time and effort available, so we're not going to do this feature any time soon.
Also, doing it properly would require some changes to the CLR. Right now the CLR treats ref-returning methods as legal but unverifiable because we do not have a detector that detects this situation:
ref int M1(ref int x)
{
return ref x;
}
ref int M2()
{
int y = 123;
return ref M1(ref y); // Trouble!
}
int M3()
{
ref int z = ref M2();
return z;
}
M3 returns the contents of M2's local variable, but the lifetime of that variable has ended! It is possible to write a detector that determines uses of ref-returns that clearly do not violate stack safety. What we would do is write such a detector, and if the detector could not prove stack safety, then we would not allow the usage of ref returns in that part of the program. It is not a huge amount of dev work to do so, but it is a lot of burden on the testing teams to make sure that we've really got all the cases. It's just another thing that increases the cost of the feature to the point where right now the benefits do not outweigh the costs.
If you can describe for me why it is you want this feature, I would really appreciate that. The more information we have from real customers about why they want it, the more likely it will make it into the product someday. It's a cute little feature and I'd like to be able to get it to customers somehow if there is sufficient interest.
(See also related questions Is it Possible to Return a Reference to a Variable in C#? and Can I use a reference inside a C# function like C++?)
Solution 2:
You are talking about methods that return a reference to a value type. The only built-in example in C# that I know of is the array-accessor of a value type:
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
and now create an array of that struct:
var points = new Point[10];
points[0].X = 1;
points[0].Y = 2;
In this case points[0]
, the array indexer, is returning a reference to struct. It is impossible to write your own indexer (for example for a custom collection), that has this same "return a reference" behavior.
I didn't design the C# language so I don't know all the reasoning behind not supporting it, but I think that the short answer might be: we can get along just fine without it.
Solution 3:
You could always do something like:
public delegate void MyByRefConsumer<T>(ref T val);
public void DoSomethingWithValueType(MyByRefConsumer<int> c)
{
int x = 2;
c(ref x);
//Handle potentially changed x...
}