Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify Optional Parameters and Nullable Optional Parameter Behavior in C#. #44408

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

shethaadit
Copy link
Contributor

@shethaadit shethaadit commented Jan 16, 2025

Summary

This PR improves the documentation for optional parameters in C# by:

  • Clarifying the distinction between nullable (T?) parameters and optional parameters with default values.
  • Highlighting that parameters can be both nullable and optional (T? allTheOptionalMeanings = default).
  • Adding examples and notes to address user confusion, ensuring better understanding of the behavior of nullable and optional parameters.
  • Maintaining all existing code snippets as they are already accurate and illustrative.

Fixes #44404


Internal previews

📄 File 🔗 Preview link
docs/csharp/programming-guide/classes-and-structs/named-and-optional-arguments.md Named and Optional Arguments (C# Programming Guide)

@shethaadit shethaadit requested review from BillWagner and a team as code owners January 16, 2025 15:42
@dotnetrepoman dotnetrepoman bot added this to the January 2025 milestone Jan 16, 2025
@dotnet-policy-service dotnet-policy-service bot added dotnet-csharp/svc fundamentals/subsvc community-contribution Indicates PR is created by someone from the .NET community. labels Jan 16, 2025
Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @shethaadit

The changes you've made emphasize the confusion rather than fixing it. A method signature can set the "default" value for an optional parameter. That's a different concept than the "default value" for a type. It also can be different than specifying a "missing" value. Consider this example:

public class Buffer<T>
{
    private T[] _storage;
    
    public Buffer(int size = 10)
    {
        _storage = new T[size];
    }
}

The "default value" for size is 10. That's different than the default value for the int type (that's 0).

@@ -70,13 +70,14 @@ The following code implements the examples from this section along with some add

## Optional arguments

The definition of a method, constructor, indexer, or delegate can specify its parameters are required or optional. Any call must provide arguments for all required parameters, but can omit arguments for optional parameters.
The definition of a method, constructor, indexer, or delegate can specify its parameters are required or optional. Any call must provide arguments for all required parameters, but can omit arguments for optional parameters. Additionally, nullable reference types (`T?`) implicitly have `null` as their default value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new sentence emphasizes the cause of the confusion, rather than removing it. We need to make a clear distinction between an optional parameter and the default value for a type.

@@ -99,7 +100,7 @@ IntelliSense uses brackets to indicate optional parameters, as shown in the foll
![Screenshot showing IntelliSense quick info for the ExampleMethod method.](./media/named-and-optional-arguments/optional-examplemethod-parameters.png)

> [!NOTE]
> You can also declare optional parameters by using the .NET <xref:System.Runtime.InteropServices.OptionalAttribute> class. `OptionalAttribute` parameters do not require a default value. However, if a default value is desired, take a look at <xref:System.Runtime.InteropServices.DefaultParameterValueAttribute> class.
> You can also declare optional parameters by using the .NET <xref:System.Runtime.InteropServices.OptionalAttribute> class. `OptionalAttribute` parameters do not require a default value. However, if a default value is desired, take a look at <xref:System.Runtime.InteropServices.DefaultParameterValueAttribute> class. Additionally, nullable types (`T?`) implicitly default to `null` without needing to use these attributes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The additional sentence here mixes an optional parameter with the default value for a type.


Each optional parameter has a default value as part of its definition. If no argument is sent for that parameter, the default value is used. A default value must be one of the following types of expressions:

- a constant expression;
- an expression of the form `new ValType()`, where `ValType` is a value type, such as an [enum](../../language-reference/builtin-types/enum.md) or a [struct](../../language-reference/builtin-types/struct.md);
- an expression of the form [default(ValType)](../../language-reference/operators/default.md), where `ValType` is a value type.
- For nullable value types or nullable reference types (`T?`), the default value is always `null`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't correct. All of these declarations are legal. They conform to the first three bullet points:

public struct S
{
}

public class C {
    void M(int? size = 5){} // a constant
    void M(string? msg = "Hello World"){} // constant
    void M(S someStruct = new S()){} // new expression, assuming `S` is a `struct`
    void M(object? o = default) { } // OK default expression
    void M(int size, S someStruct = default) {} // OK default expression addition parameter needed
    void M(S? someStruct = default) {} // OK default expression
}

@shethaadit
Copy link
Contributor Author

Hi @BillWagner, could you please check once if the updates makes sense?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community-contribution Indicates PR is created by someone from the .NET community. dotnet-csharp/svc fundamentals/subsvc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Clarification needed?
2 participants