次の方法で共有


Ref returns and ref locals

"Ref returns" are the subject of another great question from StackOverflow that I thought I might share with a larger audience.

Ever since C# 1.0 you've been able to create an "alias" to a variable by passing a "ref to a variable" to certain methods:

static void M(ref int x)
{
    x = 123;
}
...
int y = 456;
M(ref y);

Despite their different names, "x" and "y" are now aliases for each other; they both refer to the same storage location. When x is changed, y changes too because they are the same thing. Basically, "ref" parameters allow you to pass around variables as variables rather than as values. This is a sometimes-confusing feature (because it is easy to confuse "reference types" with "ref" aliases to variables,) but it is generally a pretty well-understood and frequently-used feature.

However, it is a little-known fact that the CLR type system supports additional usages of "ref", though C# does not. The CLR type system also allows methods to return refs to variables, and allows local variables to be aliases for other variables. The CLR type system however does not allow for fields that are aliases to other variables. Similarly arrays may not contain managed references to other variables. Both fields and arrays containing refs are illegal because making it legal would overly complicates the garbage collection story. (I also note that 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. For details, see the CLI specification Partition I Section 8.2.1.1, "Managed pointers and related types" for information about this feature.)

As you might expect, 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;
}

Why do this? It is quite different than a conventional "Max" which returns the larger of two values. This returns the larger variable itself, which can then be modified:

int a = 123;
int b = 456;
ref int c = ref Max(ref a, ref b);
c += 100;
Console.WriteLine(b); // 556!

Kinda neat! This would also mean that ref-returning methods could be the left-hand side of an assignment -- we don't need the local "c":

int a = 123;
int b = 456;
Max(ref a, ref b) += 100;
Console.WriteLine(b); // 556!

Syntactically, 'ref' is a strong marker that something weird is going on. Every time the word "ref" appears before a variable usage, it means "I am now making some other thing an alias for this variable". Every time it appears before a declaration, it means "this thing must be initialized with an variable marked with ref".

I know empirically that it is possible to build a version of C# that supports these features because I have done so in order to test-drive the possible feature. 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 mainstream 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 and outlaws this situation:

static ref int M1(ref int x)
{
  return ref x;
}

static ref int M2()
{
  int y = 123;
  return ref M1(ref y); // Trouble!
}
static 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. We could write such a detector, and if the detector could not prove that lifetime safety rules were met 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 we implemented this feature some day, would you use it? For what? Do you have a really good usage case that could not easily be done some other way? If so, please leave a comment. The more information we have from real customers about why they want features like this, 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. However, we also know that "ref" parameters is one of the most misunderstood and confusing features, particularly for novice programmers, so we don't necessarily want to add more confusing features to the language unless they really pay their own way.

Comments

  • Anonymous
    June 22, 2011
    I don't really see myself ever using something like this. I'm sure others would find it useful, but I imagine the majority would not.

  • Anonymous
    June 22, 2011
    The comment has been removed

  • Anonymous
    June 23, 2011
    A little off-topic... On a desktop system, rich of resources, I'd cut the "ref" accessor. I don't see any good reason to keep, especially now that the world is going toward async, and immutability is getting more importance. Anyway, C# can run even on a compact and micro frameworks, where the resources are like the water in the desert. Now, consider an array of structs (e.g. Point) and a loop to translate all of them of an offset (also a Point): for (int i=0; i<N; i++) {  pt[i].X += offset.X;  pt[i].Y += offset.Y; } Well, in this trivial case the ref is important, and would be even important if I were able to use "inline". That is because that loop is poorly performing: it has to access twice an indexer. If I add this helper: function Adder(ref Point pt, ref Point offset) {  pt.X += offset.X;  pt.Y += offset.Y; } the performance rises a lot more, because there's only one indexing, and none is copied. My question is: would be a valuable task the ability to inline-"ref" a struct of an array without having to write a separate function? Thanks a lot.

  • Anonymous
    June 23, 2011
    The comment has been removed

  • Anonymous
    June 23, 2011
    I'm with Jeff; I think maintaing this on methods might be hard. However, I wouldn't mind it on properties; it would be nice to be able to return a struct (such as Point) and you can change a property of that struct without having to copy the struct to a local, change the local and then set it back to the original property.

  • Anonymous
    June 23, 2011
    A passionate plea to NOT add this. @Mario, there are a number patterns/use cases where "ref" parameters really make good sense. For example if you are implementing an immutable system and need to update the caller with multiple new instances. Also it is a very handy paradigm when initializing read only fields and you want to factor this out of the constructor body itself. [although I wish the definition of readonly was changed...but after 5 years, I have given up even asking]

  • Anonymous
    June 23, 2011
    The comment has been removed

  • Anonymous
    June 23, 2011
    This sure would reduce the readability/maintainability of code. But that doesn't mean that it should not be implemented. Experts who need this kind of power may use it.

  • Anonymous
    June 23, 2011
    For the life of me I can't think of any uses for this in my day to day usage. I can't even think of uses for it in extreme performance scenarios when I would be willing to tolerate the conceptual complexity incurred. I'd therefore go with the 'no' option unless someone could point out some compelling use cases I think would benefit me :) The hit to the reflection/generic layer would also be quite unpleasant (especially since you don't even have the ultimate (if costly) fallback of treating it as a (possibly boxed) object.

  • Anonymous
    June 23, 2011
    Please don't add this, whenever I see a ref I'm very suspicious of what is going on. If you need C++ features use managed C++

  • Anonymous
    June 23, 2011
    I wonder what would be the practical differences between ref types as you discuss, and a generic class... public class ValueRef<T> { public T Value; } /* Untested. Ctor etc ommitted. */ The Max function mooted would instead accept two ValueRef<int> object references and return one of those. There's only one copy of the value inside, as long as all access are via x.Value. Granted, this isn't as tidy as putting the word 'ref' next to the type name, and I'm also side-stepping the question of what practical uses such an object has. (I've not tested any of this or really thought it through. Please be nice.) billpg So how do you make a ValueRef<int> to the tenth element of an integer array, say? Your idea is not so farfetched though. Something I deliberately did not mention in this article is that something like the ValueRef type you propose actually exists! It is called TypedReference and it is a Very Special Type. It is used only for obscure interop scenarios where you need to be able to pass around a reference to a variable of type where the type is not known at compile time. This is a subject for another day. -- Eric

  • Anonymous
    June 23, 2011
    I agree with Jeff. I can't think of any situations where I would actually want this.  In the strange event that I need something like this, I'll either maybe use something like Eric's ref class ( stackoverflow.com/.../2982037 ).  If someone trying to port C++ code hits an issue that requires something like this, I'd prefer solutions that avoid introducing extra syntax; it only only serves to add more ways for other people to make code less maintainable.  One of the things I like about all the Marshalling functionality is that it's mostly off to the side and ignorable until actually needed. I do see Sam's point and have encountered situations where it would have made my code slightly simpler, but every time I've hit such a situation I was able to work around it very easily.  I think supporting even that much would add more problems than it would solve.

  • Anonymous
    June 23, 2011
    Eric, I hope you'll blog about TypedReference. Not long ago, I had to write the equivalent of htmlTextWriter._attrList[index].value = someValue using Reflection. Because _attrList is an array of RenderAttribute structures, I had to get and set the entire array element just to set the value field. It seems like using FieldInfo.SetValueDirect could have made this a little more efficient.

  • Anonymous
    June 23, 2011
    Meh. As a long (long, long) time C++ user, I tend to avoid aliases. They're very difficult for the compiler/optimizer to reason with, not to mention humans. If I had a dollar for every bug... (including compiler bugs; I found and developed minimal repros for a couple dozen from Borland, a handful from GCC, and countless ones from Microsoft - no offense). Your Max() example triggers neurons in my brain associated with C preprocessor macros - that's what it mentally feels like. Maybe a better example would show how this would be useful, but I can't think of any case where I'd use this (however, I stayed up all night with my sick 23-month-old, so my brain isn't exactly 100% at the moment). I'd rather pass everything by value, even going so far as suggesting a Python-esque multiple-return-value syntax:  (resultA, resultB) = Func(); so that the "out" keyword is no longer necessary. Though I guess "ref" could still be used if somebody really had to pass a large mutable value type (not something I've ever seen recommended. Or something I've ever done after my first week in C#.). You could even treat this as a syntax-only change, converting additional return values to reference parameters under the covers. This would be nudging the language in the opposite direction of the "ref return" idea, but to my mind it would result in more clear code.

  • Anonymous
    June 23, 2011
    The comment has been removed

  • Anonymous
    June 23, 2011
    I agree with most of the other comments here - I don't think I'd use this if it were implemented, and I don't think it's really necessary.

  • Anonymous
    June 23, 2011
    I was under the impression that the general trend was moving away from mutable types and operations. I've seen ref abused quite thoroughly; mainly by those that don't (and still don't) understand the difference between reference and value types. But that's still not a good reason for rejecting a feature I'll admit. I'm more interested in the 'message' such a feature would send. "We're encouraging side-effects".

  • Anonymous
    June 23, 2011
    I have wanted a subset of this occasionally - ref returns of array elements or fields transitively of a ref type (eg "ref Ref.Struct.Struct" would be ok) would be quite useful, and (even unreturnable) local ref variables would be nice, but I wouldn't know how useful until I used this. Remember, for better or worse, in a lot of cases the alternative is public mutable fields.

  • Anonymous
    June 23, 2011
    This would definitely open up the way to some nice performance improvements in collection indexers.  For example, right now if you want to increment a value in a dictionary, you effectively have to look up the same key twice.  This can be extremely expensive  in performance-critical areas.  With ref variables though, you could just return a ref on the first lookup and increment the variable that it refers to.  Yes, refs are a little trickier to use than normal variables, but it certainly wouldn't be the most complex feature to graze the C# language.  (I mean, it already has unmanaged references and pointers.  It seems a little backwards that managed references would be omitted.)

  • Anonymous
    June 23, 2011
    Although I see its uses, I don't know if this is something I'd use because of people having troubles maintaining the code, however, if it were up to me, I'd add this feature anyway.

  • Anonymous
    June 23, 2011
    I wrote something like this recently: public class SomeClass { bool processed1; bool processed5; bool processed8; AdditionalData additionalData1/* = ... /; AdditionalData additionalData5/ = ... /; AdditionalData additionalData8/ = ... /; ProcessedData processedData1; ProcessedData processedData5; ProcessedData processedData8; public void ProcessSomething(ThingKind thingKind, ThingData data) { AdditionalData additionalData; TypedReference processedDataField; TypedReference processedField; // Initialization switch (thingKind) { case ThingKind.Thing1: additionalData = additionalData1; processedDataField = __makeref(additionalData1); processedField = __makeref(flag1); break; case ThingKind.Thing5: additionalData = additionalData5; processedDataField = __makeref(additionalData5); processedField = __makeref(flag5); break; case ThingKind.Thing8: additionalData = additionalData8; processedDataField = __makeref(additionalData8); processedField = __makeref(flag8); break; default: throw new NotSupportedException(); } // Actual processing... // Throw exceptions if there are problems // Then finish __refvalue(processedDataField, ProcessedData) = / something */; __refvalue(processedField, bool) = true; } } This code would benefit from official C# "ref locals"… (Of course, this specific method could be implemented in other ways not requiring the use of references, but most of them would end up requiring a lot more code (arrays, reflection, delegates…). Calling an external (private) method in each case label would however, perfectly work in this simple case, but would not work for more complex ones.) I felt a little shameful using those "famous" undocumented keywords, but to me the code feels much cleaner than any other way I could have ended up with. Other than this, "ref properties"as mentionned by Sam, would be quite an useful feature. The point of regular properties usually is to encapsulate a field, and do additional processing (e.g range checking, …) before setting the value. However, one may sometimes not need to verify what is written to the encapsulated field, but return an efficient reference to said field instead. Being able to write something like this might be interesting: public ref byte this[bool b, int i] { ref get { return (b ? array1 : array2)[index - 50]; } } (I chose to write "ref get", as it emphasizes the fact that it is part of a "ref property") Aditionally, considering you propose to support expressions such as: Max(ref a, ref b) += 100; Am I right assuming that this means expressions such as this one: (boolean ? ref int1 : ref int2) = 12; // would also work ? (Because this would be great to have sometimes…) Anyway, I would really like to have such a feature in the language, but I admit I wouldn't use it everyday.

  • Anonymous
    June 23, 2011
    It is common in C++ classes to have methods which returns CValueType& (for read-write) or const CValueType& (for read-only). And I did wanted that when I was learning C#. But now I am a C# guy and I changed my mind. Firstly, returning CValueType& somewhat breaks encapsulation. It makes the field modifiable to any value by other code at any time without notifying about it. It does not matter for simple case like List<>, but matters in case of Collection<T> derivatives which may need to do some action on change. Secondly, as long as CValueType& (ref return) is supported, we'd want const CValueType& (const ref return) to avoid arbitrary modification, which means introducing the tedious const-correctness thing of C++ to C#. Thirdly, it adds another way to implement read-only and read-write properties. So, I second the opinion that let the compiler/jitter to optimize out the value type overhead instead.

  • Anonymous
    June 23, 2011
    I don't mind the feature a great deal. I can't see myself using it much if at all, but it's plenty clear what's going, what with all the ref's around the place few people would ever be caught out surprised. And I have to say.. I do actually like Fabian's example above: (boolean ? ref int1 : ref int2) = 12; Despite that for performance reasons I imagine the compiler would ideally turn that into the equivelant if/else without references.

  • Anonymous
    June 23, 2011
    Please don't add this. As someone who's worked on commercial .Net systems since .Net v1, I cannot imagine a case where I'd need this; neither would I wish to maintain such a system.

  • Anonymous
    June 23, 2011
    The comment has been removed

  • Anonymous
    June 23, 2011
    (and yes, I forgot to set "operand" to null before continuing in the code above…I hope that does not detract from the comprehensibility of the example :) )

  • Anonymous
    June 23, 2011
    Pete.d's example actually shows a lovely boundary case. By working on the foreach variable you have either: Broken the (user) immutability of the variable. Added yet another confusing bug trap a la trapping them with closures Made the compiler have to spot this case and warn/refuse. Admittedly they seem to be trying to change the semantics of the variable in hypothetical vNext, but none the less as it stands I see no way this could end well.

  • Anonymous
    June 23, 2011
    I'd love this feature. Reference handling is much useful for multimedia apps.

  • Anonymous
    June 23, 2011
    I have wanted something similar in the past, when trying to modify fields inside stricts inside property-reads (such as the value of a given entry in a dictionary). Obviously, there are other ways of getting the same effect, but they aren't always as clean.

  • Anonymous
    June 23, 2011
    Although I usually like every low-level feature, I would not like to see ref locals in C#. Looking at pete.d's example, one can easily spot a lot of issues with this feature: Observe that the example relies - as most usages would - on the ability to change the variable that the reference is an alias to. But the aliasing ref local operand is declared outside the loop, which opens the question about what it refers to after the loop has terminated, given that it pointed to a loop-local variable. From the CLR point of view, this is safe, but from the C# point of view it isn't. It also concerns details like whether a loop-local variable lives in the same location in different loop iterations - this is normally true, but a simple lambda referring to the variable can change that. I think this shows that introducing ref locals in this way opens a can of worms which should remain closed. Init-once ref locals are another issue though - these would resemble C++ references rather than C++ pointers (% rather than interior_ptr if you speak C++/CLI, & rather than * if not). However, this would require a special treatment of variable initialization which C# doesn't have right now ("type local = expr;" is currently equivalent to "type local; local = expr;" - implicitly typed locals aside); I'd prefer not to change the current intuitive semantics.   Indeed, you make an excellent point which I did not call out in my sketch of the feature. In the prototype I wrote up I ensured that ref locals were "init only". There are certainly pros and cons of both ways. -- Eric   Also note that such ref local variables are of rather limited use as long as ref returns are not introduced as well, which have their own issues. Nevertheless, I somewhat agree with nonoitall regarding his comment on collection indexers; I have always found the STL indexers with their ref-returning behaviour a bit superior to the .NET approach with completely distinct getters and setters. However, I doubt that this small use case warrants such a major language change. I am glad that C++/CLI offers full support for managed pointers via % and interior_ptr; I have found this absolutely useful at times, especially when doing pointer arithmetic in arrays without needing to pin them. However, this is not really the C# way of doing things, so all in all I'd prefer not seeing managed pointer support in C# be extended beyond the current state of affairs (ref and out arguments). The only thing that slightly worries me is that this means that methods may be uncallable for C#; if I want to call a managed-pointer-returning method right now in C# 4.0, I simply get "'Class.Method()' not supported by the language". This is a bit sad, given that C# has always strived to expose every CLR feature, but I do not see a way around this.

  • Anonymous
    June 23, 2011
    It seems I have misread pete.d's example; operand never aliases a loop-local variable. This doesn't change my argument, though.

  • Anonymous
    June 23, 2011
    I would use us for a custom implementation of an array of structs, when the normal implementation is troubled. An implementation of Binary Decision Diagrams on a 32 bit architecture would be a real world case. As far as BDD's can be seen as real world, that is. Besides that, i have never even felt the desire for ref locals or ref returns, and overall life is better without them. It would be just one more dangerous pit that Jr Programmer could fall into.

  • Anonymous
    June 23, 2011
    The comment has been removed

  • Anonymous
    June 23, 2011
    Please do not put this in C# or VB.  It's applicable in only a small number of cases.  It's rarely used in C++.

  • Anonymous
    June 23, 2011
    Another thought: if we can have ref return values, can we also have "ref ref" method parameters? What about "ref ref locals and return values"? In C/C++, you can add as many levels of indirection as you like. Indeed, due to the explicitness of reference types in C/C++, it's quite common to have two levels of indirection, and three levels isn't exactly uncommon (e.g. pointer to a pointer to an array of pointers). It seems to me that C# currently strikes an effective balance between usefulness and simplicity. The "ref returns/locals" feature is way down at the bottom of the list of things that I as a programmer would appreciate seeing added to the language. It seems like it introduces a whole host of problems (including offering new, exciting ways for a programmer to make their code much more confusing), while addressing real-world, important utility issues in the language in only a tiny percentage of scenarios. We came to the same conclusion -- there are some narrow scenarios in which these techniques are extremely helpful, but they are sufficiently uncommon that we didn't want to take on the cost. If hypothetically we were to do something like this feature then we would probably not support multiple levels of refness. -- Eric

  • Anonymous
    June 23, 2011
    Ah, sorry pete. Chalk that one up to far too confusing a syntax for me then, clearly I didn't read the method properly.

  • Anonymous
    June 24, 2011
    Yeah, when I saw two different people misread the code, it was apparent that there was yet another issue with ref locals: the syntax (at least that presented here) is confusing! Presumably in the hypothetical case where this feature was implemented, a less-confusing syntax could be contrived (maybe requiring a keyword for dereferencing the alias, a la "*" but C#-ish). Somehow, I suspect it's something the C# language team doesn't have to worry about for quite a while. :)

  • Anonymous
    June 24, 2011
    >> Another thought: if we can have ref return values, can we also have "ref ref" method parameters? What about "ref ref locals and return values"? I don't think it's reasonable to treat "ref" as analogous to pointers in C++ - they're much more like references (&) in that they are bind-once with no ability to rebind, and implicitly dereferenced. And C++ doesn't have references-to-references either. Also, there's no good way to do so while keeping managed pointers (which is what "ref" is) verifiable. The moment you make a "ref ref", you create a possibility for a ref to local to escape the scope of that local. And if refs are no longer verifiable, then how are they different from unmanaged pointers? On the other hand, you can have as many levels of indirection as you want in C# already - int*** is a perfectly legal C# type.

  • Anonymous
    June 26, 2011
    Of course the most obvious use is foreach: foreach(ref var i in list)  i++; This is already possible in C++/CLI. It would be nice to have it in C# as well.

  • Anonymous
    June 27, 2011
    If it was only allowed in an "unsafe" context then it would be less likely abused and the verifier wouldn't need to be improved. Using "unsafe" for other possibly confusing/complex operations supported by the CLR, yet not supported by C#, could also lower their cost of implementation and support. Things like uninitialized locals, (ref int)obj unboxing, etc.

  • Anonymous
    June 27, 2011
    I would probably"remove" this feature with static code review tools from the teams I am going to lead. I've been on several c++ projects were the lack of readability caused by this featured costed more than we could ever have gained from it In my opinion languages should aim at gathering related information so that you for each algorithm have one locus of knowledge. This feature would distribute the knowledge of what happens to a variable making it very hard to reason about the code. Entire paradigms, like DCI (by the grand father of MVC Trygve Reenskaug supported by other noteworthies) are build on the idea of keeping knowledge of a functionality located at one place in the code

  • Anonymous
    June 27, 2011
    Asssuming the implementation would extend to lamba functions. The feature would allow an implementation of Algol 60 Call by Name.

  • Anonymous
    June 27, 2011
    The comment has been removed

  • Anonymous
    June 27, 2011
    The comment has been removed

  • Anonymous
    June 27, 2011
    The comment has been removed

  • Anonymous
    June 27, 2011
    @nonoitall I beg to disagree. the out z in my function is the equivalent of the return ref in the original function. As one who has done C++ and C++/CLI, I'll take the simplicity and cohesion of C# any day over the C++ syntax and concepts. The only place where C++ is a must is native code or asm blocks, the rest can be emulated by .net constructs.

  • Anonymous
    June 28, 2011
    @dmihailescu: Actually, nonoitall has a point here. Look at the lines "Max(ref a, ref b) += 100;" and especially "ref int c = ref Max(ref a, ref b);" in the original post. In both cases, you get a variable that will be aliased to another by the Max method (its "identity" is "switched" for you). This is not the same as putting a value in z, and then working with z. In Eric's code, you will continue to work with either a or b and you don't know which until the Max() method completes.

  • Anonymous
    June 28, 2011
    @dmihailescu:  Yeah, the original function returns a reference to A or B that can be used by the caller to modify said variable.  Your function accepts a third reference as input, but simply places a value into the variable that it points to.  It does not return a reference that the caller can use to modify one of the two original variables.  There's really no reason for the first two parameters in your function to be refs because the function only reads the values that they point to, and does nothing with the references themselves.

  • Anonymous
    June 28, 2011
    @Alan You are right. My z will be an alias  to another variable on the stack not a reference to an existing variable. I was thinking about reference objects not value types. My bad!

  • Anonymous
    June 28, 2011
    How about for databinding w/in C#: public BoundMember<T> {  private ref T _GetValueRef = ref default(T);  private ref T _SetValueRef = ref default(T);  private T _GetValue;  prviate T _SetValue;  public BoundMember(ref T value, BindingMode mode = BindingMode.TwoWay)  {    Mode = mode;    _GetValue = value;    _SetValue = value;    if(mode != BindingMode.OneWayToSource)       _GetValueRef = ref _GetValue;    if(mode == BindingMode.TwoWay || mode == BindingMode.OneWayToSource)      _SetValueRef = ref _SetValue;  }  public T Value  {    get{return _GetValue;}    set{_SetValue = value;}  }  public BindingMode{get;set;} } public enum BindingMode {  TwoWay,  OneWay,  OneWayToSource } Maybe even add syntatical sugar: int x = 0; var boundX :-: x; <=> new BoundMember(ref x); var boundX1W :- x; <=> new BoundMember(ref x, BindingMode.OneWay); var boundX1W2S -: <=> new BoundMember(ref x, BindingMode.OneWayToSource); What do you guys think?

  • Anonymous
    June 28, 2011
    I would not use it since I have never felt the need for this. At the moment, I can't think of a case where I would want it - out and ref work perfectly for me when I need to do something fancy. Indeed, I would be glad to not see this feature, as I feat it would invite people to invent new "clever" (= bad and unintelligible) coding patterns.

  • Anonymous
    June 29, 2011
    I believe you summed up the answer to your question in "Compound Assignment, Part One" ( Tue, Mar 29 2011 2:24 PM ): "we are now mutating the variable containing the copy but we need to be mutating the original." I tend to use return by reference when I want:

  • to return an lvalue.  a[5] = 0;  // a.operator = 0

  • to return this; i.e., to construct a filter chain.  See "method chaining".

  • to act on a singleton.

  • to act on someone else's storage, without having to know that their storage is stack, heap, or TEXT, or that their storage is actually someone else's storage, or that the storage is in some complicated container (so I have to be able to consume any random iterator or handle type), or that the storage is in some packed container (like an array).

  • to mutate someone else's consts.  "Yeah...  You're not allowed to change it..."

  • to act on a lazily constructed value type without forcing its entire construction at copy to stack.

  • to act on just-in-time data without forcing redundant just-in-time loads to recur at every call in a complex expression tree.

  • to get as close to an lvalue reference optimization as I can.  (I.e.  re-use the shallowest caller's return slot in their stack frame as the return slot for each callee all the way down to the deepest callee.)

  • recently, to avoid repeatedly copying multi-MB frames of video to the stack in recursive de-noising operations.  (Which, thanks to a 3rd party library writer are all value types.)  (This is more important on phones and tablets...) Admittedly, some of these overlap.  And, yes, anything can be worked around.  (Your Turing complete language is nor more powerful than my Turing ocmplete language...)  But, once one has understood the value of writing functions as filters on someone else's data, rather agnostically on how that data's stored, where that data's stored, or what operations the caller is allowed to perform on the data, it's rather cruel to take that away...  So, yeah, I think references would be a good idea for C#. Of course, sometimes, I'd really, really, really, like to know if I've been called with an lvalue or rvalue reference.  See thbecker.net/.../section_01.html for a reasonable explanation.

  • Anonymous
    June 29, 2011
    @Jason Lind - your example has ref fields in a class, which isn't allowed in the CLR. But ultimately a reference to a "variable" of any kind can be treated as two operations, a getter and a setter. And thanks to lambdas you can express operations very neatly, and they can refer to local variables, so you can already simulate that kind of binding very easily, see smellegantcode.wordpress.com/.../pointers-to-value-types-in-c

  • Anonymous
    June 29, 2011
    @Eric Towers - Based on the examples you're giving (e.g. realtime video processing), you're not really describing C#'s sweet spot. If safe-mode C# absorbed all the features it needed to replace C as a "portable assembly language", it would be no different from unsafe-mode C#. Although I confess that as a recovering long-term C++ user, I've found it shamefully entertaining to learn about rvalue references. But I'm going to keep it as pure entertainment. I think it's going to work best that way for me!

  • Anonymous
    June 29, 2011
    It seems a little confusing to me that we already have ref returns in array indexers: Consider following example: struct S {   int i;   public void Increment() {i++;} } S[] s = new S[1]; s[0].i++; // s[0].i equals to 1 because s[0] returns managed pointer to interior array element IList<S> si = s; si[0].i++; //compile time error, because we can't modify temporary variable si[0].Increment(); // compiled successfully but increment local copy It's clear why we have ref returns on arrays (it improves performance) but why we have ref returns in arrays but do not have ref returns in BCL collections? It seems like we could add this behavior to existing collections without adding any new features to C# compiler at all. P.S. Actually I can't find specification section that stated about returning "managed reference" from arrays indexer. I know that array indexer implemented with its own IL instruction called ldelema, but I can't find official rational about it.

  • Anonymous
    June 30, 2011
    The comment has been removed

  • Anonymous
    July 04, 2011
    I would use it! I need it right now Can you give us more details? -- Eric

  • Anonymous
    July 23, 2011
    I feel like it would be useful to have ref returns if you could combine this with ref parameters for operators as well. It would allow doing math operations for example on complex types (Matrices) without having to worry about it copying the thing so many times. This can of course be inlined by hand, but inling so many adds and multiplies begs for a better way to do it. Working with XNA in C# 4 it can be a burden to do Vector / Matrix math when worrying about performance as well, especialy with very complex matrix hierarchies and blended animations using 100's or 1000's or matrix multiplies per model (with many many value copies as well)

  • Anonymous
    October 05, 2011
    Since I see a lot of people saying "Don't add this!" I feel compelled to add my vote to the "yes" side. I think of C# as being a better C++. I would love nothing better than to stop using C++ and use C# exclusively, because the safety guarantees, rich BCL, improved intellisense, shorter code, faster compile times (etc.) of C# are invaluable. Unfortunately, I still have to use C++ extensively because C# is not fast enough---especially on .NET Compact Framework which is sometimes more than 10 times slower than equivalent C# code (see www.codeproject.com/.../BenchmarkCppVsDotNet.aspx ). As mentioned earlier, ref-types could let you get a reference to a value in a Dictionary and modify that value with a single lookup, and ref-types would allow you to write more concise code in some cases (and I agree with Yaron Minsky about the value of concision, see queue.acm.org/detail.cfm ), such as the stated example that you want to modify the result of Max(ref x, ref y). Even if this is never allowed in C#, surely it should be officially supported by the CLR standards (not just MS' implementation) so that compilers for 3rd-party languages can "safely" include the feature. (Same argument goes for covariant return types.)

  • Anonymous
    November 14, 2012
    If implemented I would use it today, and have used it last night. I desire to access the STL/CLR but cannot do so in C# because all the interfaces have prototypes with TValue% return types.  Yet, given the knowledge that all C# reference types and boxed value types are on the managed heap and that the STL/CLR is using 'by-value' semantics, it is safe to convert these to TValue%. The only missing piece is for the C# compiler to recognize this and do its magic, recognizng that the C# implementation public  TValue  get_ref() { return _container[_bias]; } satisfes the interface prototype public  TValue%  get_ref(); In fact the MSDN documentation here msdn.microsoft.com/.../bb302608.aspx states that this will happen, but it doesn't. Pieter