{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "C#",
   "language": "csharp",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "csharp"
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "id": "rec00",
   "metadata": {},
   "source": "# Record Types\n\nYou have been writing `record` since Chapter 9 as a shorthand for simple data types.\nHere we look at what `record` actually provides and when to prefer it over a `class`.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "rec01",
   "metadata": {},
   "source": "## What `record` Gives You\n\nA `record` is a reference type (like a `class`) with four things added automatically:\n\n1. **Value-based equality** \u2014 two records are equal if all their properties are equal\n2. **`ToString()`** \u2014 prints all property values readably\n3. **Deconstruction** \u2014 unpack into variables like a tuple\n4. **`with` expressions** \u2014 create a copy with selected properties changed",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "rec02",
   "metadata": {},
   "source": "### Value-Based Equality",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "rec03",
   "metadata": {},
   "source": "record Point(int X, int Y);\n\nvar a = new Point(1, 2);\nvar b = new Point(1, 2);\nvar c = new Point(3, 4);\n\nConsole.WriteLine(a == b);   // True  \u2014 same values\nConsole.WriteLine(a == c);   // False\nConsole.WriteLine(a);        // Point { X = 1, Y = 2 }",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "rec04",
   "metadata": {},
   "source": "### `with` Expressions\n\nCreate a modified copy without mutating the original.",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "rec05",
   "metadata": {},
   "source": "record Person(string Name, int Age);\n\nvar alice = new Person(\"Alice\", 30);\nvar olderAlice = alice with { Age = 31 };\n\nConsole.WriteLine(alice);       // Person { Name = Alice, Age = 30 }\nConsole.WriteLine(olderAlice);  // Person { Name = Alice, Age = 31 }\nConsole.WriteLine(alice == olderAlice);  // False",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "rec06",
   "metadata": {},
   "source": "### Deconstruction",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "rec07",
   "metadata": {},
   "source": "record Point(int X, int Y);\n\nvar p = new Point(3, 7);\nvar (x, y) = p;\nConsole.WriteLine($\"x={x}, y={y}\");  // x=3, y=7",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "rec08",
   "metadata": {},
   "source": "## Positional vs. Standard Records\n\n```csharp\n// Positional \u2014 compact; properties are init-only\nrecord Point(int X, int Y);\n\n// Standard \u2014 more control over property visibility/mutability\nrecord Person\n{\n    public string Name { get; init; } = \"\";\n    public int    Age  { get; set;  }\n}\n```\n\nUse **positional** for immutable value-like data (coordinates, domain events, DTO return values). Use **standard** when some properties need to be mutable.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "init00",
   "metadata": {},
   "source": "## Init-Only Properties\n\n`init` is like `set`, but only callable during object construction. It makes individual properties settable at creation time while remaining immutable afterward \u2014 without needing a positional record.\n\n```csharp\nrecord Person\n{\n    public string Name { get; init; } = \"\";\n    public int    Age  { get; init; }\n}\n```\n\nThis is what the compiler generates automatically for positional record properties.",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "init01",
   "metadata": {},
   "source": "record Person\n{\n    public string Name { get; init; } = \"\";\n    public int    Age  { get; init; }\n}\n\nvar p = new Person { Name = \"Alice\", Age = 30 };\nConsole.WriteLine(p);  // Person { Name = Alice, Age = 30 }\n\n// p.Age = 31;  // compile error \u2014 init-only after construction\n\n// Works fine in object initializer:\nvar q = p with { Age = 31 };  // creates a copy\nConsole.WriteLine(q);  // Person { Name = Alice, Age = 31 }",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "init02",
   "metadata": {},
   "source": "Init-only properties are also common in regular classes when you want immutable-after-creation semantics without making the whole type a record:\n\n```csharp\nclass Config\n{\n    public string Host { get; init; } = \"localhost\";\n    public int    Port { get; init; } = 8080;\n}\n```",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "rec09",
   "metadata": {},
   "source": "## `record struct`\n\n`record struct` gives the same conveniences on a *value type* \u2014 allocated on the stack, copied on assignment.\n\n```csharp\nrecord struct Size(int Width, int Height);\n```\n\nPrefer `record struct` for tiny, frequently-created data (e.g., 2D coordinates in a game loop). Prefer `record` (class) for everything else.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "rec10",
   "metadata": {},
   "source": "## `record` vs. `class` vs. `struct`\n\n| | `class` | `record` | `struct` / `record struct` |\n|---|---|---|---|\n| Equality | Reference | Value | Value |\n| `with` expression | \u2717 | \u2713 | \u2713 |\n| Auto `ToString` | \u2717 | \u2713 | \u2713 |\n| Heap allocated | \u2713 | \u2713 | \u2717 |\n| Inheritance | \u2713 | \u2713 | \u2717 |\n\nUse `record` when your type is primarily **data** \u2014 no complex behaviour, identity does not matter, immutability is preferred.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "rec11",
   "metadata": {},
   "source": "## Practice\n\n1. Define `record Temperature(double Celsius)` and add a computed property `Fahrenheit`. Print two equal temperatures and verify `==` is `true`.\n2. Using `with`, create a sequence: start with `Person(\"Bob\", 20)`, then produce versions at age 21, 22, 23 without mutation.\n3. Define `record struct Vector2(float X, float Y)` and write an `Add` method that returns a new `Vector2`.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "rec12",
   "metadata": {},
   "source": "```{rubric} Footnotes\n```",
   "outputs": []
  }
 ]
}