{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bcae055f",
   "metadata": {},
   "source": [
    "```{index} built-in types; C# type system\n",
    "```\n",
    "# Types"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cdc243ad",
   "metadata": {},
   "source": [
    "In C#, **everything is a type**. Every value you store, every variable you declare, and every expression you write has a type. A **type** defines three things:\n",
    "\n",
    "- **Value**: The **set of valid values** it can hold (e.g., `int` holds whole numbers −2,147,483,648 to 2,147,483,647).\n",
    "- **Operation**: The **operations** permitted on those values (e.g., arithmetic on numbers, `.Length` on strings).\n",
    "- **Memory**: The **amount of memory** reserved when a variable of that type is created.\n",
    "\n",
    "C# types can be grouped into two groups: **value** types and **reference** types.\n",
    "\n",
    "**Value types**: \n",
    "- Variables of value types directly contain their data.\n",
    "- Value types include **primitive** types `int`, `double`, `bool`, `char`, `string`, and `struct` and `enum`. \n",
    "- Despite their keyword status, each is simply an alias for a .NET struct or class in the `System` namespace. For example, `int` aliases `System.Int32` and `string` aliases `System.String`. [^1]\n",
    "\n",
    "**Reference types**:\n",
    "- Variables of reference types store references to their data (objects).\n",
    "- Reference types include `class`, `interface`,`delegate`, and `record`.\n",
    "- You can define your own types; their fields and properties are themselves typed with built-ins or other custom types. \n",
    "- There are three **built-in reference** types:  `object`, `string`, `delegate`, and `dynamic`.\n",
    "\n",
    "Note that:\n",
    "- `struct` vs `class` is a common C# interview question because they look similar but `struct` is a value type (copied) and `class` is a reference type (shared).\n",
    "- `string` is the famous exception: it's technically a reference type, but behaves like a value type because it's immutable. Reassigning a string always creates a new one rather than modifying the original.\n",
    "\n",
    "Types split into two fundamental categories:\n",
    "\n",
    "| | **Value Types** | **Reference Types** |\n",
    "|---|---|---|\n",
    "| Storage | Stored directly in the variable | Variable holds a reference to heap memory |\n",
    "| Assignment | Copies the value | Copies the reference (both point to the same object) |\n",
    "| Default value | `0` / `false` / `'\\0'` | `null` |\n",
    "| Built-in examples | `int`, `long`, `double`, `float`, `decimal`, `bool`, `char` | `string`, `object` |\n",
    "| User-defined examples | `struct`, `enum`, `record struct` | `class`, `interface`, `delegate`, `record` |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a5a7df8",
   "metadata": {},
   "source": [
    "## Common Data Types in C\\#\n",
    "\n",
    "C# is a \"strongly typed\" language, meaning that every variable and constant has a type.\n",
    "In addition to variables, types are also required for expressions that evaluate to a\n",
    "value, method declarations with names, input parameters, and return values. Examples\n",
    "of common value types (declared and initiated with value assignment) are as follows.\n",
    "\n",
    "```csharp\n",
    "int myNum = 5;                  // Integer (whole number)\n",
    "long myNum = 15000000000L;      // Integer\n",
    "double myDoubleNum = 5.99D;     // Floating point number\n",
    "char myLetter = 'D';            // Character\n",
    "bool myBool = true;             // Boolean\n",
    "string myText = \"Hello\";        // String\n",
    "```\n",
    "\n",
    "From the list above you may notice that C# requires number **suffixes** for\n",
    "numeric types. The purpose of using suffixes is to help the compiler unambiguously\n",
    "identify the data type of the value/literal. The basic rules for integral\n",
    "literal number suffixes are:\n",
    "\n",
    "- If an integral literal has no suffix, its type is the first of the following types in\n",
    "  which its value can be represented: int, uint, long, ulong.\n",
    "- l or L for long\n",
    "- U or u for unsigned integer\n",
    "- UL or ul for unsigned long\n",
    "\n",
    "For floating-point numeric types:\n",
    "\n",
    "- The number literal without suffix or with the d or D suffix is of type double\n",
    "- f or F suffix is of type float\n",
    "- m or M suffix is of type decimal\n",
    "\n",
    "A purpose of defining data types is for memory allocation. Examples of some\n",
    "defined types and their memory size can be seen in the table below.\n",
    "\n",
    "| No. | Group | Type | Size | Precision | Description |\n",
    "|-----|-------|------|------|-----------|-------------|\n",
    "| 1 | **Integer** | `byte` | 1 byte/8 bits | | Integral range 0 to 255 (no negative values) |\n",
    "| 2 | | `short` | 16 bits | | Integral range -32,768 to 32,767 |\n",
    "| 3 |  | **\\*** **`int`** | 4 bytes/32 bits | | Integral range -2,147,483,648 to 2,147,483,647 |\n",
    "| 4 | | `long` | 8 bytes/64 bits | | Integral range -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |\n",
    "| 5 | **Floating Point** | **\\*** `float` | 4 bytes/32 bits | ~6-9 digits | Fractional numbers |\n",
    "| 6 |  | **`double`** | 8 bytes/64 bits | ~15-17 digits | Fractional numbers, general math |\n",
    "| 7 | | `decimal` | 16 bytes/128 bits | 28-29 digits | Fractional numbers, high precision (use for money) |\n",
    "| 8 | **Boolean** | **\\*** **`bool`** | 1 bit | | True or false values |\n",
    "| 9 | **Text** | `char` | 2 bytes | | Single character, single quotes `'A'` |\n",
    "| 10 |  | **\\*** **`string`** | 2 bytes per character | | Sequence of characters, double quotes `\"Hello\"` |\n",
    "\n",
    "Choosing types is a design decision to meet the needs of different use scenarios.\n",
    "For example, for financial unit, the *decimal* type may be a better choice because it\n",
    "is designed for the purpose of holding a larger range of digits with higher precision.\n",
    "\n",
    "One attribute of the integral value data types is that they can be either signed or\n",
    "unsigned. A signed type uses its bytes to represent an equal number of positive\n",
    "and negative numbers; whereas an unsigned type (such as `ushort`, `uint`,\n",
    "and `ulong`) uses its bytes to represent only positive numbers. The difference between\n",
    "singed and unsigned numbers can be seen from the example below:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "224a9d15",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Signed integral types:\n",
      "sbyte   : -128 to 127 \t\t\t\t\t (max: 2^8-1)\n",
      "short  : -32768 to 32767 \t\t\t\t (max: 2^15-1)\n",
      "int    : -2147483648 to 2147483647    \t\t\t (max: 2^31-1)\n",
      "long   : -9223372036854775808 to 9223372036854775807 \t (max: 2^63-1)\n",
      "\n",
      "Unsigned integral types:\n",
      "byte   : 0 to 255     \t\t\t\t\t (2^8)\n",
      "ushort : 0 to 65535 \t\t\t\t\t (2^16)\n",
      "uint   : 0 to 4294967295 \t\t\t\t (2^32)\n",
      "ulong  : 0 to 18446744073709551615 \t\t\t (2^64)\n"
     ]
    }
   ],
   "source": [
    "Console.WriteLine(\"Signed integral types:\");\n",
    "Console.WriteLine($\"sbyte   : {sbyte.MinValue} to {sbyte.MaxValue} \\t\\t\\t\\t\\t (max: 2^8-1)\");\n",
    "Console.WriteLine($\"short  : {short.MinValue} to {short.MaxValue} \\t\\t\\t\\t (max: 2^15-1)\");\n",
    "Console.WriteLine($\"int    : {int.MinValue} to {int.MaxValue}    \\t\\t\\t (max: 2^31-1)\");\n",
    "Console.WriteLine($\"long   : {long.MinValue} to {long.MaxValue} \\t (max: 2^63-1)\");\n",
    "\n",
    "Console.WriteLine(\"\");\n",
    "\n",
    "Console.WriteLine(\"Unsigned integral types:\");\n",
    "Console.WriteLine($\"byte   : {byte.MinValue} to {byte.MaxValue}     \\t\\t\\t\\t\\t (2^8)\");\n",
    "Console.WriteLine($\"ushort : {ushort.MinValue} to {ushort.MaxValue} \\t\\t\\t\\t\\t (2^16)\");\n",
    "Console.WriteLine($\"uint   : {uint.MinValue} to {uint.MaxValue} \\t\\t\\t\\t (2^32)\");\n",
    "Console.WriteLine($\"ulong  : {ulong.MinValue} to {ulong.MaxValue} \\t\\t\\t (2^64)\");"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56d477bf",
   "metadata": {},
   "source": [
    "\n",
    "You should see the output as below:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a7dce1f",
   "metadata": {},
   "source": [
    "```text\n",
    "Signed integral types:\n",
    "sbyte  : -128 to 127\n",
    "short  : -32768 to 32767\n",
    "int    : -2147483648 to 2147483647\n",
    "long   : -9223372036854775808 to 9223372036854775807\n",
    "\n",
    "Unsigned integral types:\n",
    "byte   : 0 to 255\n",
    "ushort : 0 to 65535\n",
    "uint   : 0 to 4294967295\n",
    "ulong  : 0 to 18446744073709551615\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c1a3c586",
   "metadata": {},
   "source": [
    "```{index} C# type system; value type; reference type\n",
    "```\n",
    "\n",
    "### C# Built-in Type System\n",
    "\n",
    "C# is a **statically typed** language — every value has a type known at compile\n",
    "time. Types fall into two fundamental categories:\n",
    "\n",
    "```text\n",
    "C# Types\n",
    "├── Value Types          (stored directly on the stack)\n",
    "│   ├── Simple Types\n",
    "│   │   ├── Integral     sbyte  byte  short  ushort  int  uint  long  ulong  char\n",
    "│   │   ├── Floating     float  double\n",
    "│   │   ├── Decimal      decimal\n",
    "│   │   └── Boolean      bool\n",
    "│   ├── Enum Types       (user-defined named constants)\n",
    "│   └── Struct Types     (user-defined value types)\n",
    "└── Reference Types      (stored on the heap; variable holds a reference)\n",
    "    ├── Class Types      string  object  and user-defined classes\n",
    "    ├── Interface Types\n",
    "    ├── Array Types\n",
    "    └── Delegate Types\n",
    "```\n",
    "\n",
    "**Value types** hold their data directly. Assigning one value-type variable to\n",
    "another *copies* the value. **Reference types** hold a reference (memory\n",
    "address) to the data; assigning one reference-type variable to another copies\n",
    "the reference, not the data itself.\n",
    "\n",
    "Each C# primitive type is an alias for a .NET struct in the `System` namespace —\n",
    "for example, `int` is `System.Int32`, `bool` is `System.Boolean`, and `string`\n",
    "is `System.String`.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12f0d5e0",
   "metadata": {},
   "source": [
    "```{index} data types in action\n",
    "```\n",
    "\n",
    "## Data Types in Action\n",
    "\n",
    "The following subsections explore each built-in type through examples you can\n",
    "run in `csharprepl`.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7d2432a",
   "metadata": {},
   "source": [
    "```{index} integer type; int; long; byte; sbyte\n",
    "```\n",
    "\n",
    "### Integer Types\n",
    "\n",
    "**Integer types** store whole numbers with no fractional part. The most common\n",
    "choice is `int` (32-bit signed), which covers roughly ±2.1 billion. Use `long`\n",
    "(64-bit) when you need a larger range, or `byte` for small non-negative values\n",
    "(0–255).\n",
    "\n",
    "Unsigned variants (`uint`, `ulong`, `ushort`, `byte`) hold only non-negative\n",
    "values, which doubles the positive range but disallows negatives.\n",
    "\n",
    "Numeric literals default to `int`. Use suffixes to specify other types:\n",
    "`L`/`l` for `long`, `U`/`u` for `uint`, `UL`/`ul` for `ulong`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aab41809",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "int population = 2_147_483_647;        // int max (~2.1 billion); _ is a digit separator\n",
    "long worldPopulation = 8_000_000_000L; // needs L suffix — too large for int\n",
    "byte age = 25;                         // 0–255, no negative values\n",
    "sbyte temperature = -10;               // -128–127\n",
    "uint score = 1_000_000U;               // unsigned: 0–4.29 billion\n",
    "\n",
    "// Signed vs unsigned: same bits, different interpretation\n",
    "int  signed   = -1;\n",
    "uint unsigned = (uint)signed;           // becomes 4294967295 (all bits set)\n",
    "signed\n",
    "unsigned"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7726ba4a",
   "metadata": {},
   "source": [
    "```{index} floating-point type; float; double; decimal\n",
    "```\n",
    "\n",
    "### Floating-Point Types\n",
    "\n",
    "C# has three types for fractional numbers:\n",
    "\n",
    "| Type | Size | Precision | Suffix | Use for |\n",
    "|------|------|-----------|--------|---------|\n",
    "| `float` | 32-bit | ~6–9 digits | `f` or `F` | Graphics, sensors |\n",
    "| `double` | 64-bit | ~15–17 digits | `d` or `D` (default) | General math |\n",
    "| `decimal` | 128-bit | 28–29 digits | `m` or `M` | Money, finance |\n",
    "\n",
    "`double` is the default type for decimal literals. Use `decimal` whenever\n",
    "rounding errors are unacceptable (e.g., currency); never use `float`/`double`\n",
    "for money.\n",
    "\n",
    ":::{important}\n",
    "Floating-point arithmetic is approximate — `0.1 + 0.2` does not equal `0.3`\n",
    "exactly in binary representation.\n",
    "\n",
    "This is not a C# bug; it is a consequence of how computers store fractional\n",
    "numbers. Memory stores bits (0s and 1s), so values are encoded in **base 2\n",
    "(binary)**. Just as 1/3 cannot be written exactly in base 10 (0.3333…), many\n",
    "decimal fractions — including 0.1 and 0.2 — cannot be represented exactly in\n",
    "binary. The closest representable binary value is used instead, and when you\n",
    "add two of these approximations the tiny errors accumulate, giving a result\n",
    "like `0.30000000000000004` instead of `0.3`.\n",
    "\n",
    "For money or anything where exact decimal rounding matters, use `decimal`,\n",
    "which stores numbers in base 10 internally and avoids this problem entirely.\n",
    ":::\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b7026f2d",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "float  f = 3.14F;\n",
    "double d = 3.141592653589793;    // default decimal literal type\n",
    "decimal price = 19.99M;          // use M suffix for decimal\n",
    "\n",
    "// Precision difference\n",
    "0.1 + 0.2                        // 0.30000000000000004 — binary rounding\n",
    "0.1M + 0.2M                      // 0.3 — decimal is exact\n",
    "f.GetType()\n",
    "d.GetType()\n",
    "price.GetType()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70a1904f",
   "metadata": {},
   "source": [
    "```{index} boolean type; bool\n",
    "```\n",
    "\n",
    "### Boolean (`bool`)\n",
    "\n",
    "A `bool` holds exactly one of two values: `true` or `false`. It is the result\n",
    "of any comparison or logical expression, and is the required type for `if`\n",
    "conditions and loop guards.\n",
    "\n",
    "Unlike C/C++, C# does **not** allow integers to be used as booleans — `if (1)`\n",
    "is a compile-time error.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db60a9d4",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "bool isOnline   = true;\n",
    "bool hasExpired = false;\n",
    "\n",
    "int x = 7;\n",
    "bool inRange = x > 0 && x < 10;   // true\n",
    "bool isEven  = x % 2 == 0;        // false\n",
    "\n",
    "isOnline\n",
    "inRange\n",
    "isEven\n",
    "isEven.GetType()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "360957ae",
   "metadata": {},
   "source": [
    "```{index} character type; char; Unicode\n",
    "```\n",
    "\n",
    "### Character (`char`)\n",
    "\n",
    "`char` represents a single Unicode UTF-16 character, written in **single\n",
    "quotes**. Internally it is stored as a 16-bit unsigned integer, so it can be\n",
    "cast to and from `int`. Common escape sequences:\n",
    "\n",
    "| Sequence | Meaning |\n",
    "|----------|---------|\n",
    "| `'\\n'` | Newline |\n",
    "| `'\\t'` | Tab |\n",
    "| `'\\\\'` | Backslash |\n",
    "| `'\\''` | Single quote |\n",
    "\n",
    "Note that `'A'` (char) is different from `\"A\"` (string of length 1).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c1a1ad4",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "char letter  = 'A';\n",
    "char digit   = '7';\n",
    "char newline = '\\n';\n",
    "char unicode = '\\u00E9';       // é — U+00E9 LATIN SMALL LETTER E WITH ACUTE\n",
    "\n",
    "// char ↔ int\n",
    "int  code = letter;            // 65 — implicit cast to int\n",
    "char back = (char)(code + 1);  // 'B' — explicit cast back\n",
    "\n",
    "letter\n",
    "code\n",
    "back\n",
    "unicode"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba4b8dcc",
   "metadata": {},
   "source": [
    "(string)=\n",
    "\n",
    "```{index} string type; string interpolation; verbatim string\n",
    "```\n",
    "\n",
    "### String (`string`)\n",
    "\n",
    "`string` is a sequence of `char` values, written in **double quotes**. Strings\n",
    "are **immutable** — operations like concatenation return a new string.\n",
    "\n",
    "Key features:\n",
    "- **Interpolation**: embed expressions with `$\"...{expr}...\"`\n",
    "- **Verbatim literals**: prefix with `@` to treat backslashes literally (useful\n",
    "  for file paths)\n",
    "- **Common members**: `.Length`, `.ToUpper()`, `.ToLower()`, `.Contains()`,\n",
    "  `.Substring()`, `.Replace()`, indexing with `[i]`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44e37469",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "string name    = \"Alice\";\n",
    "string greeting = $\"Hello, {name}!\";     // string interpolation\n",
    "string path    = @\"C:\\Users\\Alice\\docs\"; // verbatim: backslashes are literal\n",
    "\n",
    "// Common operations\n",
    "name.Length                              // 5\n",
    "name.ToUpper()                           // \"ALICE\"\n",
    "name[0]                                  // 'A' — char at index 0\n",
    "name.Contains(\"lic\")                     // true\n",
    "name.Replace(\"Alice\", \"Bob\")             // \"Bob\"\n",
    "\n",
    "greeting\n",
    "path"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b4f845e",
   "metadata": {},
   "source": [
    "A string is a **sequence of characters** — each character has a numeric\n",
    "index starting at `0`. For example, in `\"formosa\"`, `'f'` is at index 0\n",
    "and `'a'` is at index 6. The last character is always at index `length - 1`.\n",
    "\n",
    "| Index     | 0 | 1 | 2 | 3 | 4 | 5 | 6 |\n",
    "|-----------|---|---|---|---|---|---|---|\n",
    "| Character | f | o | r | m | o | s | a |\n",
    "\n",
    "When represented in code, indexing works like the example below.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "79a9625b",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a\n"
     ]
    }
   ],
   "source": [
    "string txt = \"ilha formosa\";\n",
    "Console.WriteLine(txt[3]);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebb291a3",
   "metadata": {},
   "source": [
    "Note that, in the example above, the output is a character since strings consist of characters. Note that the `char` type literals are created by delimiting the characters by **single quotation** marks."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31b90ef1",
   "metadata": {},
   "source": [
    "### Creating a String\n",
    "\n",
    "There are many ways to declare and initialize a variable of type string, most of them involve using an assignment statement to assign the variable with a value.\n",
    "\n",
    "As an example, to create a string variable in C# REPL:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ea07f693",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "string dayOfWeek = \"Monday\"; \n",
    "dayOfWeek"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "416c8828",
   "metadata": {},
   "source": [
    "For the different ways of [declaring and initializing](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#declaring-and-initializing-strings) a string variable, see below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "6e60c1ea",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1. \n",
      "2. \n",
      "3. \n",
      "4. c:\\Program Files\\Microsoft Visual Studio 8.0\n",
      "5. c:\\Program Files\\Microsoft Visual Studio 9.0\n",
      "6. Hello World!\n",
      "7. I'm still a strongly-typed System.String!\n",
      "8. You can't get rid of me!\n",
      "9. System.Char[]\n",
      "10. ABC\n"
     ]
    }
   ],
   "source": [
    "#pragma warning disable CS8632\n",
    "\n",
    "using System.Runtime.InteropServices;\n",
    "\n",
    "string message1;                // Declare without initializing.\n",
    "string? message2 = null;        // Initialize to null.\n",
    "string message3 = System.String.Empty;  // Initialize as an empty string use the Empty constant instead of the literal \"\".\n",
    "string oldPath = \"c:\\\\Program Files\\\\Microsoft Visual Studio 8.0\";  // Initialize with a regular string literal.\n",
    "string newPath = @\"c:\\Program Files\\Microsoft Visual Studio 9.0\";   // Initialize with a verbatim string literal.\n",
    "System.String greeting = \"Hello World!\";    // Use System.String if you prefer.\n",
    "var temp = \"I'm still a strongly-typed System.String!\"; // In local variables (i.e. within a method body) you can use implicit typing.\n",
    "const string message4 = \"You can't get rid of me!\"; // Use a const string to prevent 'message4' from being used to store another string value.\n",
    "char[] letters = { 'A', 'B', 'C' }; // Use the String constructor only when creating a string from a char*, char[], or sbyte*. See System.String documentation for details.\n",
    "string alphabet = new string(letters);\n",
    "\n",
    "Console.WriteLine(\"1. \" + message1);\n",
    "Console.WriteLine(\"2. \" + message2);\n",
    "Console.WriteLine(\"3. \" + message3);\n",
    "Console.WriteLine(\"4. \" + oldPath);\n",
    "Console.WriteLine(\"5. \" + newPath);\n",
    "Console.WriteLine(\"6. \" + greeting);\n",
    "Console.WriteLine(\"7. \" + temp);\n",
    "Console.WriteLine(\"8. \" + message4);\n",
    "Console.WriteLine(\"9. \" + letters);\n",
    "Console.WriteLine(\"10. \" + alphabet);\n",
    "\n",
    "#pragma warning restore CS8632"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "227a0f30",
   "metadata": {},
   "source": [
    "Since this is a console app, we use the TERMINAL in VS Code to do `dotnet run` to see the project outcome. Make sure you are in the right project directory, though."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53dc59a1",
   "metadata": {},
   "source": [
    "```{index} string; concatenation\n",
    "```\n",
    "\n",
    "(string-concatenation)=\n",
    "\n",
    "### String Concatenation\n",
    "\n",
    "String concatenation is to join stings together. In C#, the `+` operator is used to perform concatenation. Note C# uses the `+` operator for both arithmetic addition and concatenation. To concatenate two strings together:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "e588e593",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tsangyao Chen"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "string firstName = \"Tsangyao\";    // assign value to variable\n",
    "string lastName = \" Chen\";\n",
    "\n",
    "firstName + lastName              // concatenation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ca3d71e",
   "metadata": {},
   "source": [
    "\n",
    "C# can also concatenate values of different data types. The example below\n",
    "shows you how to concatenate data of string type and int type:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22f89798",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "int aLargeAmountOf = 400;\n",
    "\"I spent \" + aLargeAmountOf + \" dollars on coffee this week.\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2221ddff",
   "metadata": {},
   "source": [
    "### Escape Special Characters\n",
    "\n",
    "```{index} escape code; \\g<2>\n",
    "```\n",
    "\n",
    "Since C# requires double quotation marks as delimiters for creating strings, when we need\n",
    "to show quotation marks as part of a string, the situation becomes tricky. Consider the\n",
    "following string toBe1. We see that there is a syntax error at (1,18) (line# 1, character# 18)\n",
    "when trying to put a quotation inside the string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "874b96a2",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "(1,18): error CS1002: ; expected\n",
      "\n",
      "(1,25): error CS1044: Cannot use more than one type in a for, using, fixed, or declaration statement\n",
      "\n",
      "(1,28): error CS1002: ; expected\n",
      "\n",
      "(1,35): error CS1002: ; expected\n",
      "\n",
      "(1,37): error CS1002: ; expected\n",
      "\n"
     ]
    },
    {
     "ename": "Error",
     "evalue": "compilation error",
     "output_type": "error",
     "traceback": []
    }
   ],
   "source": [
    "string toBe1 = \"\"To be, or not to be\" is a speech given by Prince Hamlet.\";"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ba9fdeb",
   "metadata": {},
   "source": [
    "To make the quotation work, we need to use the special character backslash `\\` as *escape character*,\n",
    "meaning that the character following it should be treated specially: They turns\n",
    "special characters into string characters."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6385020",
   "metadata": {},
   "source": [
    "string toBe2 = \"\"To be, or not to be\" is a speech given by Prince Hamlet.\";\n",
    "\n",
    "Console.WriteLine(toBe2);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00287840",
   "metadata": {},
   "source": [
    "In our example above, the `\"` in `\\\"To be` and `to be\\\"` are escaped and\n",
    "therefore special character `\"` can be treated as string and shown as intended.\n",
    "\n",
    "Another example would look like the following."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "5f53fcdb",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Goog morning!\n",
      "He said, \"Goog morning!\".\n"
     ]
    }
   ],
   "source": [
    "Console.WriteLine(\"Goog morning!\");\n",
    "Console.WriteLine(\"He said, \\\"Goog morning!\\\".\");"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d63fc570",
   "metadata": {},
   "source": [
    "Common special cases to be escaped include:\n",
    "\n",
    "| Escape character | Result                              |\n",
    "| ---------------- | ----------------------------------- |\n",
    "| `\\\"`             | `\"` (quote)                         |\n",
    "| `\\'`             | `'` ( single quote in char literal) |\n",
    "| `\\\\`             | `\\` (backslash)                     |\n",
    "| `\\n`             | new line                            |\n",
    "| `\\t`             | new tab                             |\n",
    "\n",
    "The newline character (`\\n`) inserts a new line and move the cursor\n",
    "to the beginning of the new line. This is useful because C# string literals\n",
    "are characters delimited by double quotation marks `\"` in one line. [^footnote-1] To\n",
    "print to multiple lines, we use `\\n` like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "528a7e4b",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Good morning. Good afternoon. Good evening.\n",
      "Good morning. \n",
      "Good afternoon. \n",
      "Good evening.\n"
     ]
    }
   ],
   "source": [
    "Console.WriteLine(\"Good morning. Good afternoon. Good evening.\");\n",
    "Console.WriteLine(\"Good morning. \\nGood afternoon. \\nGood evening.\");"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "101afd7c",
   "metadata": {},
   "source": [
    "(more-string-methods)=\n",
    "\n",
    "### String Properties and Methods\n",
    "\n",
    "Although we use string literals, strings are objects. In object-oriented-programming,\n",
    "objects have *instance properties* and *instance methods*. Some examples of C# string\n",
    "properties and methods are:\n",
    "\n",
    "The length of a string can be found using the `Length` property:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "a001a943",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The length of the txt string is: 26\n"
     ]
    }
   ],
   "source": [
    "string txt = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n",
    "Console.WriteLine(\"The length of the txt string is: \" + txt.Length);\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a32ad303",
   "metadata": {},
   "source": [
    "\n",
    "There are many string methods available [^footnote-2]. As examples, ToUpper() and ToLower()\n",
    "return a copy of the string converted to uppercase or lowercase:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "cf8b85e9",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "HELLO WORLD\n",
      "hello world\n"
     ]
    }
   ],
   "source": [
    "string txt = \"Hello World\";\n",
    "Console.WriteLine(txt.ToUpper());   // Outputs \"HELLO WORLD\"\n",
    "Console.WriteLine(txt.ToLower());   // Outputs \"hello world\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cea9beda",
   "metadata": {},
   "source": [
    "```{index} type conversion; casting\n",
    "```\n",
    "\n",
    "## Type Conversion\n",
    "\n",
    "C# variables have specific types, but values sometimes need to move between\n",
    "types. Type conversions are either **implicit** (automatic) or **explicit**\n",
    "(manual cast required).\n",
    "\n",
    "**Implicit casting** happens automatically when converting a smaller type to a\n",
    "larger one — no data is lost:\n",
    "\n",
    "```text\n",
    "char → int → long → float → double\n",
    "```\n",
    "\n",
    "**Explicit casting** is required when converting a larger type to a smaller one,\n",
    "because precision or range may be lost:\n",
    "\n",
    "```text\n",
    "double → float → long → int → char\n",
    "```\n",
    "\n",
    "For example:\n",
    "\n",
    "```csharp\n",
    "int a = 123;\n",
    "long b = a;        // implicit: int fits in long, no cast needed\n",
    "int c = (int) b;   // explicit: long → int, cast required\n",
    "```\n",
    "\n",
    "Use `GetType()` to inspect a variable's type at runtime. When types are *not*\n",
    "cast properly, C# raises a compile-time error. For example, assigning a `double`\n",
    "directly to an `int` fails:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f7191c06",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "double d = 2.0;\n",
    "int i = d;"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1175a152",
   "metadata": {},
   "source": [
    "Note that if you choose to agree with the message and perform a type casting, you lose the\n",
    "precision of `double` over an `int`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ed369cc1",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "double d = 2.5;       // create a double type variable d\n",
    "d\n",
    "int i;                // declare an int without value assignment\n",
    "i                     // get the (default) value of an int\n",
    "i = (int)d;           // explicitly telling the compiler you intend the conversion\n",
    "i                     // get the value of i; the value .5 is lost"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0997686",
   "metadata": {},
   "source": [
    "```{index} Round function\n",
    "```\n",
    "\n",
    "Rounding is similar to casting a floating type to possible as it gives us an `int` type.\n",
    "The function `Math.Round` will round to a mathematical integer, but leaves\n",
    "the type unchanged. So we need to perform a type casting after rounding:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c878cdc",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "d\n",
    "d.GetType()\n",
    "d = Math.Round(d);        // rounding and re-assignment\n",
    "d\n",
    "d.GetType()               // the type remains\n",
    "i = (int)Math.Round(d);   // casting to int\n",
    "i\n",
    "i.GetType()               // type correct"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a9c6d30",
   "metadata": {},
   "source": [
    "Casting from int to double is usually not necessary but cause of implicit conversion.\n",
    "A use case for this would be when doing divisions, where `double` would work better than\n",
    "`int`. As an example, using csharprepl, we see that:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a787c9d",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "int denominator = 3;\n",
    "int numerator = 14;\n",
    "numerator / denominator               // an integer division\n",
    "(double) numerator / denominator      // intended operation; casting required"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44661966",
   "metadata": {},
   "source": [
    "```{rubric} Footnotes\n",
    "```\n",
    "\n",
    "[^1]: For the full C# type system reference, see the \n",
    "[Types section in C# reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types).\n",
    "\n",
    "[^footnote-1]: You can use [verbatim text](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/verbatim) to achieve multiple line text.\n",
    "[^footnote-2]: See [String methods](https://learn.microsoft.com/en-us/dotnet/api/system.string?view=net-8.0#methods) for a complete list."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5633e3f",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "language,-all",
   "main_language": "csharp",
   "notebook_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "polyglot-notebook",
   "version": ""
  },
  "polyglot_notebook": {
   "kernelInfo": {
    "defaultKernelName": "csharp",
    "items": [
     {
      "aliases": [],
      "name": "csharp"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
