{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "display_name": "C#",
      "language": "csharp",
      "name": "csharp"
    },
    "language_info": {
      "name": "csharp"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "id": "nul00",
      "metadata": {
        "language": "markdown"
      },
      "source": "# Nullable Types and Null Operators\n\n`null` is the source of countless runtime crashes. Modern C# (8+) provides tools to make null-handling explicit, safe, and concise.",
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "nul01",
      "metadata": {
        "language": "markdown"
      },
      "source": "## Nullable Value Types\n\nBy default, value types (`int`, `double`, `bool`) cannot be `null`. Append `?` to opt in:\n\n```csharp\nint  x = null;   // compile error\nint? y = null;   // OK\n```\n\nCheck before use with `.HasValue` / `.Value`, or use the null operators below.",
      "outputs": []
    },
    {
      "cell_type": "code",
      "id": "nul02",
      "metadata": {
        "language": "csharp"
      },
      "source": "int? score = null;\n\nif (score.HasValue)\n    Console.WriteLine($\"Score: {score.Value}\");\nelse\n    Console.WriteLine(\"No score yet.\");\n\n// Shorthand with null-coalescing\nint display = score ?? 0;\nConsole.WriteLine($\"Display: {display}\");  // Display: 0",
      "outputs": [],
      "execution_count": null
    },
    {
      "cell_type": "markdown",
      "id": "nul03",
      "metadata": {
        "language": "markdown"
      },
      "source": "## Nullable Reference Types (C# 8+)\n\nEnable with `#nullable enable` (or project-wide via `<Nullable>enable</Nullable>`).\nOnce enabled, `string` means *non-nullable*; `string?` means *may be null*.\nThe compiler warns if you dereference a potentially-null reference.",
      "outputs": []
    },
    {
      "cell_type": "code",
      "id": "nul04",
      "metadata": {
        "language": "csharp"
      },
      "source": "#nullable enable\n\nstring  name = \"Alice\";   // cannot be null\nstring? nick = null;      // may be null\n\n// Console.WriteLine(nick.Length);  // warning: dereference of possibly null\nConsole.WriteLine(nick?.Length);  // OK — prints nothing if null",
      "outputs": [],
      "execution_count": null
    },
    {
      "cell_type": "markdown",
      "id": "nul05",
      "metadata": {
        "language": "markdown"
      },
      "source": "## The Null Operators\n\n| Operator | Name | Meaning |\n|---|---|---|\n| `x ?? y` | Null-coalescing | Return `x` if not null, else `y` |\n| `x ??= y` | Null-coalescing assignment | Assign `y` to `x` only if `x` is null |\n| `x?.Member` | Null-conditional | Access `Member` only if `x` is not null |\n| `x?[i]` | Null-conditional index | Index only if `x` is not null |\n| `x!` | Null-forgiving | Suppress the nullable warning (use sparingly) |",
      "outputs": []
    },
    {
      "cell_type": "code",
      "id": "nul06",
      "metadata": {
        "language": "csharp"
      },
      "source": "// ?? — null-coalescing\nstring? input = null;\nstring result = input ?? \"(none)\";\nConsole.WriteLine(result);  // (none)\n\n// ??= — assign only if null\ninput ??= \"default\";\nConsole.WriteLine(input);  // default\n\n// ?. — null-conditional chain\nstring[]? words = null;\nint? len = words?.Length;\nConsole.WriteLine(len);  // (nothing printed — len is null)",
      "outputs": [],
      "execution_count": null
    },
    {
      "cell_type": "markdown",
      "id": "nul07",
      "metadata": {
        "language": "markdown"
      },
      "source": "### Chaining `?.` and `??`\n\nCombine them for safe, concise access with a fallback.",
      "outputs": []
    },
    {
      "cell_type": "code",
      "id": "nul08",
      "metadata": {
        "language": "csharp"
      },
      "source": "record Order(string? CustomerName, Address? ShippingAddress);\nrecord Address(string City, string Zip);\n\nOrder? order = null;\n\n// Safe deep access with fallback\nstring city = order?.ShippingAddress?.City ?? \"Unknown\";\nConsole.WriteLine(city);  // Unknown",
      "outputs": [],
      "execution_count": null
    },
    {
      "cell_type": "markdown",
      "id": "nul09",
      "metadata": {
        "language": "markdown"
      },
      "source": "## Pattern Matching and Null\n\nPattern matching integrates cleanly with nullability:\n\n```csharp\nstring? s = GetValue();\n\nstring result = s switch\n{\n    null              => \"(none)\",\n    { Length: 0 }    => \"(empty)\",\n    _                 => s\n};\n```",
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "nul10",
      "metadata": {
        "language": "markdown"
      },
      "source": "## Practice\n\n1. Write `int SafeParse(string? input)` that returns the parsed integer, or `0` if `input` is null or not a valid number. Use `int.TryParse`.\n2. Given `List<string?> names`, use LINQ and `??` to produce a `List<string>` where every null is replaced with `\"Anonymous\"`.\n3. Rewrite this safely using null operators:\n   ```csharp\n   if (user != null && user.Address != null)\n       Console.WriteLine(user.Address.City);\n   ```",
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "nul11",
      "metadata": {
        "language": "markdown"
      },
      "source": "```{rubric} Footnotes\n```",
      "outputs": []
    }
  ]
}
