34

Can I return a reference to a double value for example?

This is what I want to do:

ref double GetElement()
{
   ......
   // Calculate x,y,z
   return ref doubleArray[x,y,z];
}

To use it like this

void func()
{
   GetElement()=5.0;
}

It is like returning a double pointer in C++ ... I know that the way I wrote it is wrong.. but is there a correct way for doing it?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Betamoo
  • 14,964
  • 25
  • 75
  • 109
  • do you want to assign the element to the array or get its value? Do you want a function that reads something or writes something? – Axarydax Dec 27 '10 at 23:18
  • I want to assign a value in the caller function.. – Betamoo Dec 27 '10 at 23:19
  • Not only can't you do this, you're trying to return a reference to an instance of a value type. I don't even know what that would _mean_. – John Saunders Dec 27 '10 at 23:20
  • That is the problem, I do not know a way to return a reference for double not a value ... – Betamoo Dec 27 '10 at 23:22
  • @John Saunders, I think it would mean something in C++ (not with the same syntax, of course)... but I'm a bit rusty in C++ so I'm not sure – Thomas Levesque Dec 27 '10 at 23:22
  • `double` is a value type. Period. – John Saunders Dec 27 '10 at 23:23
  • 2
    That's not the point. In C++ (not C++/CLI), there is no concept of value/reference type. You could perfectly have a reference to a double (not a reference in the .NET sense, of course): `int x = 42; int& y = x;`. Anyway, I'm afraid that's not very helpful for the OP ;) – Thomas Levesque Dec 27 '10 at 23:44
  • 2
    @John Saunders: No, it does **not** mean "trying to return a reference to an **instance** of a value type". It means trying to return a reference to **a variable of value type**, which is perfectly sensible and legal in the CLR type system. A variable has a location, a type and a lifetime; as long as the lifetime is known to be not shorter than the lifetime of the reference, it is legal to make a reference to such a variable. (In the CLR type system, not in C#.) Remember **an array element is a variable, not a value.** – Eric Lippert Dec 28 '10 at 01:32
  • @Eric: Thanks. I thought an element of an array of a value type was just a value, not a variable. – John Saunders Dec 28 '10 at 02:11
  • 1
    If you're interested in this: I think (although I'd have to check) that this is allowed by the Common Language Runtime (with managed references), but C# just doesn't support it. – user541686 Dec 28 '10 at 02:20
  • @Lambert. Correct. See my answer. – Eric Lippert Dec 28 '10 at 05:40
  • 2
    Am I the only one that thinks that the example the OP provided is a code smell? It seems strange to me to be assigning to a method that gets something. Or for that matter, assigning something to a method at all... – jasonh Dec 28 '10 at 06:34

5 Answers5

44

UPDATE: The desired feature is now supported in C# 7.


The CLR type system does support ref-returning methods, and I have written an experimental prototype of the C# compiler which supports the feature you want. (The prototype also implements ref-typed local variables, but ref-typed fields are illegal in the CLR type system.)

You have hit upon exactly the syntax I chose for the prototype, which means that either great minds think alike, or that fools never differ.

Though the prototype works quite nicely, it is very unlikely that this will make the bar to become a feature of the next version of the C# language. Very few customers want this feature, it is fairly expensive to implement, we have a list as long as your arm of more important features, and there are other ways to make this sort of thing work without adding this complexity to the type system. These are all huge "points against" doing the feature.

For example, you could make a pair of delegates:

struct Ref<T>
{
    private readonly Func<T> getter;
    private readonly Action<T> setter;
    public Ref(Func<T> getter, Action<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }
    public T Value { get { return getter(); } set { setter(value); } }
}

var arr = new int[10];
var myref = new Ref<int>(()=>arr[1], x=>arr[1]=x);
myref.Value = 10;
Console.WriteLine(myref.Value);

That is considerably slower than the same feature implemented with ref returns, but the benefit is that you can make a Ref<T> in places where ref is not legal. For example, you can store Ref<T> in a field, which you cannot do with a ref-returning method.

If you have a really awesome compelling scenario for why you need ref-returning methods, I would love to hear about it. The more real-world scenarios we have, the more likely it is that such a feature might get implemented in a hypothetical future version of the language.

See also related questions:

Can I use a reference inside a C# function like C++?

Why doesn't C# support the return of references?

and my blog post on the subject:

http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • I have a scenario, which I doubt qualifies as awesome or compelling, but I do run into over an over again: a class that exposes a struct as a property. If only `Class.Struct.Property = value` could be supported, it would be possible to efficiently update that value. As it is you have to use `Class.Struct = new Struct { Property = value }` or add redundant helper properties to `Class`. Even `Ref` doesn't solve this problem. – Rick Sladkey Jan 03 '11 at 23:38
  • @Rick: that's yet another reason why mutable structs are a worst practice. If you want to mutate a part of a particular instance of a struct then you are treating it like a reference type; make it a reference type in the first place. – Eric Lippert Jan 03 '11 at 23:48
  • 6
    I agree conceptually, but mutable structs that look like reference types are essential for efficiency. If allocating/freeing a million reference instances were as fast a a million structs, it wouldn't be an issue! – Rick Sladkey Jan 04 '11 at 00:05
  • 2
    @EricLippert: Assume one has a mutable class `PointClass` with `Int32` field or properties called `X` and `Y`, and one has an `IList myList`. Is there any halfway-decent way to allow `myList[2].X = 5;` to work without allowing outside code to make future modifications to `myList[2].X` without going through `myList`? Given an `IList myList2`, code like `{var tmp=myList2[2]; tmp.X = 5; myList[2] = tmp;`} is clearer and safer than anything I can imagine for classes. Since a `Point` is semantically a pair of integers, why not use a data type that behaves like one? – supercat Nov 14 '12 at 23:30
  • Of course, if `myList[2]` could return a `Point&`, then code could be written in the clearest idiomatic fashion without the evils of exposing promiscuous references to mutable objects. – supercat Nov 14 '12 at 23:31
  • @EricLippert been a while since this story was posted, but the single most compelling reason to want to allow this is when you start running into GC performance problems and start needing to move large amounts of data into structs to stop killing the GC (especially when they migrate to the 2nd gen collection and then get tossed). https://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collector – Kendall Bennett Mar 19 '16 at 22:53
  • @EricLippert, am I correct in understanding that this functionality has finally been introduced into the language ([docs](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/ref-returns))? Does this answer deserve to be updated? – kmote May 08 '18 at 15:45
  • 1
    @kmote: **Read the answer again**. I updated it in 2017. Note the bit in ALL CAPS that says "UPDATE". So yes, it should be updated, and it was. – Eric Lippert May 08 '18 at 15:59
  • 1
    @kmote: Now, if you want to spend effort on updating the site, my recommendation is that you get the *question* deleted, rather than updating the answers. This question is (1) a duplicate, and (2) predicated on a now-false assumption. It will take some work to get it deleted, as other questions mark this one as their duplicate. – Eric Lippert May 08 '18 at 17:03
10

Update

This feature has been added to C# 7. You can use syntax just like you posted in your question. For example:

double[,,] doubleArray = new double[10,10,10];

ref double GetElement()
{
   var (x,y,z) = (1,2,3);
   return ref doubleArray[x, y, z];
}

Eric Lippert's answer goes into detail. I would probably delete this answer, but as it's the accepted answer I cannot delete it.

Original Answer

Value types in C# are always passed by value. Objects always have their reference passed by value. This changes in "unsafe" code as Axarydax points out.

The easiest, safest way to avoid this constraint is to make sure that your double is attached to an object somehow.

public class MyObjectWithADouble {
    public double Element {get; set;} // property is optional, but preferred.
}

...
var obj = new MyObjectWithADouble();
obj.Element = 5.0

I also want to remark that I'm a little confused about how you anticipate assigning a double to a three-dimensional array. You might want to clarify what you're going for.

I think I understand a little better what you're going for now. You want to return the location of the value in a given array, and then be able to change the value in that location. This pattern breaks some of the expected paradigms of C#, so I would suggest considering other ways to achieve what you're looking for. But if it really makes sense to do it, I'd do something more like this:

public class 3dArrayLocation {public int X; public int Y; public int Z;}

...

public 3dArrayLocation GetElementLocation(...)
{
    // calculate x, y, and z
    return new 3dArrayLocation {X = x, Y = y, Z = z}
}

...

var location = GetElementLocation(...);
doubleArray[location.X, location.Y, location.Z] = 5.0;
Community
  • 1
  • 1
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
8

No, this is not possible in C#. You can only pass parameters by reference.

However, you could achieve the same result with a property:

double Element
{
    get { return doubleArray[x,y,z]; }
    set { doubleArray[x,y,z] = value; }
}

void func()
{
   Element = 5.0;
}
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
6

You could do it in unsafe code and have a method that returns a pointer to double:

unsafe double* GetElementP(){
...
}
Axarydax
  • 16,353
  • 21
  • 92
  • 151
  • Although this is possible, I wouldn't recommend it... there are probably better ways of solving the problem, but the OP needs to give more details about what he wants to do – Thomas Levesque Dec 27 '10 at 23:41
  • You'd have to fix the array in place so that the garbage collector does not move it. – Eric Lippert Dec 28 '10 at 01:20
  • 1
    @Eric: I know this might be somewhat off-topic for you, but it would be awfully nice if someone blogged about how C++/CLI's `interior_ptr` and `pin_ptr` map into the CLR type system, how C#'s pointer variables compare, and whether there's any C# equivalent for the C++/CLI pointers. – Ben Voigt Dec 28 '10 at 16:10
  • @Ben: Stan Lippman or Herb Sutter would be better people to ask for the C++/CLI details; I am not conversant with them. The C# equivalent of a C++ pinned pointer is a local variable of pointer type declared using the "fixed" statement. – Eric Lippert Dec 28 '10 at 16:15
1

After some thinking, why not send the value to be set with the function like this:

void SetElement(double value)
{
   ......
   // Calculate x,y,z
   doubleArray[x,y,z]=value;
}

and use it:

void func()
{
   SetElement(5.0);
}

However, I will still choose one of your helpful answers...

Betamoo
  • 14,964
  • 25
  • 75
  • 109