Why out parameters are required to be initialized inside both try and catch sections?
Asked Answered
H

4

5

I've noticed that C# compiler (.NET 4.5.2) doesn't allow me to compile the following code:

public void Test(out string value)
{
    //value = null;

    try
    {
        value = null;
    }
    catch (Exception ex)
    {
        //value = null;
    }
}

It fails with the following error:

The out parameter 'value' must be assigned to before control leaves the current method

But if I'm uncommenting the assignment in the catch section, it compiles successfully.
Obviously, it also compiles when I'm uncommenting the assignment before the try statement.

So the question is why it's insufficient to have the initialization of an out parameter inside a try block? Why am I forced to do the initialization in the catch block as well?

Hyper answered 4/9, 2015 at 18:46 Comment(3)
this code never fails but compiler does not check it at compile time.This
@M.kazemAkhgary: How do you know it never fails? Before null can be stored in the variable, it has to be pushed onto the stack with a ldnull. There is no reason that couldn't cause a StackOverflowException or something.Dearly
@DarkFalcon Please add that as an answer - all other answers simply cite the language spec. I was looking for an actual reason but couldn't think up one.Memo
T
1

The compiler does not have enough smarts to understand that the code in a try-block could have multiple parts, parts that won't fail and parts that might fail.

The fact that you've initialized the out parameter inside the try-block is simply enough for the compiler, anything inside the try-block might not happen at all and thus the out parameter might not have been given a value before the method returns, and thus you get the error.

When you add the initialization to the catch-block you are basically saying (in terms of what the compiler can understand) that I understand that the code in the try-block might not have executed fully or at all, so please ensure this is done before you continue.

Typographer answered 4/9, 2015 at 19:7 Comment(1)
No, the compiler does have enough smarts to know that the try block can fail at any point, even before the assignment, which it can. It would be invalid to assume that the try block must assign the value.Gourmont
J
7

The reason is because the out keyword guarantees that the parameter will be assigned to before the method is exited. As such, if and exception is raised before the value = null; line executes and there is no assignment to that parameter in the catch block, that guarantee is broken.

If would be the same if you had an if else statement where one of the two logical blocks did not perform an assignment.

As noted by the MSDN, out and ref are similar in that assignments made to this parameter will carry themselves out of the method, but ref does not make this same guarantee. So if the desired result is a try catch where there is not an assignment in the catch block, then perhaps you want the ref keyword.

Additionally, if this assignment is to be the final line of execution in the try block, you could logically move it into a finally block, which guarantees it will execute if an exception is thrown in the try and, as such, satisfies the requirements of an out.

Jebel answered 4/9, 2015 at 18:48 Comment(5)
At first I wanted to write something similar but an if..else is markedly different from initializing the variable as the first actual statement inside the try. If the try doesn't execute, there's not even a guarantee that the catch will execute.Memo
@Memo on that case program will stop working! so there is no more stepsThis
@M.kazemAkhgary Yes. This wouldn't prevent the compiler from understanding that the variable is already initialized in the try block.Memo
@M.kazemAkhgary If your other comment (under the question) is valid, this is just a case of missing optimization and the language requirement. I wonder if there's a technical reason for requiring the initialization in catch.Memo
What is the wisdom behind this requirement? if I initialize Count=0 and then call a function foo(..., out Count); that only should increment Count if it found matches, why should the function update Count otherwise? I don't want it to. Thank you.Kalsomine
P
3

You must set the out parameter in your function body. Because code in the try block may or may not execute (since an error could be thrown and control could be transferred to your error handler), you must set the variable somewhere before you leave the function. In the catch block is a valid place, as is before/after the try { ... } catch{ ... }, or in the finally { ... } block

Propositus answered 4/9, 2015 at 18:51 Comment(1)
What is the wisdom behind this requirement? if I initialize Count=0 and then call a function foo(..., out Count); that only should increment Count if it found matches, why should the function update Count otherwise? I don't want it to. Thank you.Kalsomine
L
3

According to C# Sepcification, which says

All output parameters of a function member must be definitely assigned at each location where the function member returns (through a return statement or through execution reaching the end of the function member body). This ensures that function members do not return undefined values in output parameters, thus enabling the compiler to consider a function member invocation that takes a variable as an output parameter equivalent to an assignment to the variable.

In case of try..catch the function could return either from Try or from catch. So there are two execution paths so as per the spec compiler does compile time checks if output parameters has assigned a value in both execution paths.

A solution to your problem would be to assign a default value to the out parameter. Later you can initialize it in Try with proper value and compiler won't bother you.

Lactation answered 4/9, 2015 at 18:58 Comment(0)
T
1

The compiler does not have enough smarts to understand that the code in a try-block could have multiple parts, parts that won't fail and parts that might fail.

The fact that you've initialized the out parameter inside the try-block is simply enough for the compiler, anything inside the try-block might not happen at all and thus the out parameter might not have been given a value before the method returns, and thus you get the error.

When you add the initialization to the catch-block you are basically saying (in terms of what the compiler can understand) that I understand that the code in the try-block might not have executed fully or at all, so please ensure this is done before you continue.

Typographer answered 4/9, 2015 at 19:7 Comment(1)
No, the compiler does have enough smarts to know that the try block can fail at any point, even before the assignment, which it can. It would be invalid to assume that the try block must assign the value.Gourmont

© 2022 - 2024 — McMap. All rights reserved.