mafu
mafu

Reputation: 32710

Does C# support call-by-result?

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.

Upvotes: 2

Views: 398

Answers (4)

Kirill Shlenskiy
Kirill Shlenskiy

Reputation: 9587

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;
}

Upvotes: 0

Hans Passant
Hans Passant

Reputation: 942109

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.

Upvotes: 2

Alexei Levenkov
Alexei Levenkov

Reputation: 100555

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.

Upvotes: 2

Z .
Z .

Reputation: 12837

Short answer - no, it does not.

Upvotes: 3

Related Questions