# C#: Nullable params vs default params

While both **nullable type parameters** and **default parameters** are used to make method arguments optional, they solve entirely different problems.

Nullable types define what data a variable can hold (allowing it to be `null`), whereas default parameters define what value a method will use if the caller doesn't provide one.

## **The Code Comparison**

### **1\. Using a Nullable Type as parameter**

When you use a nullable type as a parameter, the caller **must** pass a value (or explicitly pass `null`). Inside the method, you must check if a value exists before using it.

```csharp
// The caller is forced to explicitly pass a value or null
void PrintScore(int? score)
{
    if (score.HasValue)
    {
        Console.WriteLine($"Score is: {score.Value}");
    }
    else
    {
        Console.WriteLine("No score provided.");
    }
}

// How you call it:
PrintScore(100);  // Output: Score is: 100
PrintScore(null); // Output: No score provided.
// PrintScore();  // ❌ Compile Error: No argument given that corresponds to the required parameter.
```

### **2\. Using a Default Parameter**

When you use a default parameter, you assign a fallback value using the `=` operator in the method signature. The caller can completely omit the argument when calling the method.

```csharp
// The caller can omit this argument entirely. If they do, 'score' defaults to 0.
void PrintScore(int score = 0)
{
    // No null check needed; 'score' is a normal, safe integer.
    Console.WriteLine($"Score is: {score}");
}

// How you call it:
PrintScore(100); // Output: Score is: 100
PrintScore();    // Output: Score is: 0 (Omitted, used the default)
```

## **Direct Comparison**

| **Feature** | **Nullable Type Parameters (**`T?`**)** | **Default Parameters (**`T param = value`**)** |
| --- | --- | --- |
| **Primary Purpose** | Allows a variable to represent a **missing, unassigned, or undefined state** (`null`). | Allows a method argument to be **omitted by the caller**, falling back to a pre-defined value. |
| **Call Syntax** | The caller **must** explicitly pass a value or `null`. | The caller **can skip** the argument entirely. |
| **Inside the Method** | You must safely check for `null` (`HasValue` or `!= null`) before using it. | The variable is immediately ready to use with a guaranteed, non-null value. |
| **Value Restriction** | Can only represent the valid range of the type **plus** `null`. | Can be assigned any compile-time constant default value (e.g., `0`, `"Guest"`, `false`). |

## **Combining Both Parameters**

There are times when you want to combine both patterns. For example, in C# this won't work:

```csharp
void ProcessTransaction(decimal amount, DateTime transactionDate = DateTime.UtcNow) // ❌ THIS WILL NOT COMPILE. Error: The expression being assigned to 'transactionDate' must be a constant
{   
    Console.WriteLine($"Processing ${amount} on {transactionDate}");
}
```

`DateTime.UtcNow` is a runtime property, not a compile-time constant.

In C#, default parameters are baked directly into the calling application's code at compile time. Because `DateTime.UtcNow` changes every millisecond, the compiler cannot determine its value when building your application.

The only default values allowed for a standard `DateTime` parameter are compile-time constants, such as `default` (which evaluates to `1/1/0001 12:00:00 AM`).

**The Working Idiomatic Solution**

To achieve exactly what you want (making the date optional and defaulting to the exact moment the method runs), you must combine the nullable type with a `null` constant default parameter:

```csharp
void ProcessTransaction(decimal amount, DateTime? transactionDate = null)
{
    // 1. 'null' is a valid compile-time constant for a nullable type.
    // 2. The ?? operator can now be used because transactionDate CAN be null.
    DateTime finalDate = transactionDate ?? DateTime.UtcNow;
    
    Console.WriteLine($"Processing ${amount} on {finalDate}");
}
```

Thanks for reading and I hope this was helpful.
