2

I'm aware of 3 parameter evaluation types in C#:

  1. default, which is by-value
  2. ref, which is by-ref
  3. out, which is by-ref but considered initially uninitialized and mandatory to assign

My professor stated that C# also supports by-result, which he explained as:

  1. Argument has to be LHS-compatible
  2. Create local copy of argument and operate on that
  3. After successful processing of method body, write value of copy back to the parameter source

I don't see how this refers to any of the above types.

mafu
  • 28,708
  • 38
  • 138
  • 232
  • That and `ref` would produce the same result in both cases; maybe he got confused. – Ry- Jul 09 '14 at 02:03
  • @false No, because ref updates the parameter source immediately, while this does only afterwards. – mafu Jul 09 '14 at 02:05
  • 1
    It sounds like your professor is talking about calls like this: `a = f(a)`. – Sergey Kalinichenko Jul 09 '14 at 02:05
  • @dasblinkenlight No, he was talking about 'regular' calls (e.g. `int i = 1; f(i);` now i is 2) – mafu Jul 09 '14 at 02:09
  • 1
    Maybe lambda with captures? Like `Action f = v => i = 2*v; f(i);`? – Alexei Levenkov Jul 09 '14 at 02:12
  • @AlexeiLevenkov Possibly - could you add this an a complete answer? If I understand your example right then it does work here. Even though I'd think that he did not intend to use the functional paradigm here, he would technically be correct then! – mafu Jul 09 '14 at 02:19
  • @mafu: Er, sorry, I meant “most” rather than “both”. – Ry- Jul 09 '14 at 02:24
  • you can make that work only with params that are not objects (simple values or structs) – Z. Danev Jul 09 '14 at 02:25

4 Answers4

3

Short answer - no, it does not.

Z. Danev
  • 11,848
  • 1
  • 29
  • 48
2

While it is not clear what teacher meant, it is possible to get code that textually match something like

 int i = 1; f(i); //now i is 2

by using lambda expression that captures local variable.

int i = 1;
Action<int> f = v => i = 2 * v; 
f(i); 
Console.WriteLine(i); // now i is 2

Note that i in call to f is passed strictly "by value". It could be as well f(42) - parameter does not have any impact on what variable will be changed as result of execution.

Alexei Levenkov
  • 94,391
  • 12
  • 114
  • 159
2

No, not an explicit C# language feature. It does not suffer from major aliasing problems, the kind that are common when a language only supports pass-by-reference or has pointers as a first-order language feature. And very little syntax to make threading easier, beyond the lock keyword.

One rule in C# that helps is that it forbids passing a property by reference, a problem that can only be solved by call-by-result. Notable is that VB.NET doesn't have this rule and solves it by implementing call-by-result automatically. This does have a knack for causing surprises.

It does occur in practice on a MarshalByRefObject that lives in another execution context. Like another AppDomain or another machine. Necessarily so, a ref argument needs to be copied across the context boundary before the call and copied back afterwards. This is however largely transparent to the program, not counting a quirk that requires applying the [Out] attribute explicitly.

Community
  • 1
  • 1
Hans Passant
  • 873,011
  • 131
  • 1,552
  • 2,371
0

I think your professor might be referring to plain variable reassignment upon method completion (i.e. i = DoSomething(i)), or possibly operators which result in variable reassignment under the covers, i.e. ++.

To illustrate this:

class Immutable
{
    public readonly int Value;

    public Immutable(int value)
    {
        this.Value = value;
    }

    public static Immutable operator ++(Immutable obj)
    {
        return new Immutable(obj.Value + 1);
    }
}

Now we can do the following:

Immutable a = new Immutable(1);
Immutable originalA = a;

Debug.Assert(a.Value == 1);
Debug.Assert(a == originalA); // Same instance (obviously).

a++;

Debug.Assert(a.Value == 2);
Debug.Assert(a != originalA); // New instance.

This appears to satisfy all criteria:

  • You can perform LHS assignment on a variable of type Immutable.
  • The operator method receives a copy of the original variable (you can reassign obj inside the body of the method, it won't affect the original location).
  • a is reassigned once the operator has finished executing, and will point to the newly-created instance.

EDIT

While this is definitely not the answer as it does not satisfy any of the points, I think it's worth mentioning that you can also get the "by ref" semantics by passing around pointers, which I am sure everyone knows. What some may not know, however, is that this can also be done using TypedReference, which is a special beast in MS C#:

void DodgyIncrement()
{
    int i = 0;

    this.Increment(__makeref(i));

    Debug.Assert(i == 1);
}

void Increment(TypedReference i)
{
    __refvalue(i, int) += 1;
}
Kirill Shlenskiy
  • 8,623
  • 24
  • 37