From 9a7a4f393a405ca5bbaabb9b92a8186919d7b461 Mon Sep 17 00:00:00 2001
From: Sandipan Mohanty <s.mohanty@fz-juelich.de>
Date: Sun, 8 May 2022 20:31:00 +0200
Subject: [PATCH] Add first day notebooks

---
 notebooks/BlocksScopesNamespaces.ipynb |  637 ++++++++++
 notebooks/Functions.ipynb              | 1529 ++++++++++++++++++++++++
 notebooks/Fundamentals_1.ipynb         |  720 +++++++++++
 notebooks/Fundamentals_2.ipynb         | 1048 ++++++++++++++++
 4 files changed, 3934 insertions(+)
 create mode 100644 notebooks/BlocksScopesNamespaces.ipynb
 create mode 100644 notebooks/Functions.ipynb
 create mode 100644 notebooks/Fundamentals_1.ipynb
 create mode 100644 notebooks/Fundamentals_2.ipynb

diff --git a/notebooks/BlocksScopesNamespaces.ipynb b/notebooks/BlocksScopesNamespaces.ipynb
new file mode 100644
index 0000000..2c85e11
--- /dev/null
+++ b/notebooks/BlocksScopesNamespaces.ipynb
@@ -0,0 +1,637 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "f9bbdd7a-2dc4-4f0a-b4b6-2eeaecbfec05",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 1,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "#pragma cling add_include_path(\"/p/project/training2213/local/include\")\n",
+    "#include <iostream>\n",
+    "#include <string>\n",
+    "#include <cmath>\n",
+    "using namespace std;"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "international-german",
+   "metadata": {},
+   "source": [
+    "## Blocks\n",
+    "\n",
+    "We can group a number of statements into a block by simply enclosing them inside a pair of braces `{` and `}`. Blocks are convenient to group statements together. For instance,\n",
+    "\n",
+    "```c++\n",
+    "if (x > 1) {\n",
+    "    x = sqrt(log(x));\n",
+    "    std::cout << \"x decreased to \" << x << \"\\n\";\n",
+    "} else {\n",
+    "    x = 1;\n",
+    "    std::cout << \"x clamped to 1\\n\";\n",
+    "}\n",
+    "```\n",
+    "We wanted to execute two statements when a condition is true and 2 different statements when it is false. Note how the statements are grouped together using the braces. Although frequently C++ programmers use indentation to make such groupings easy to see, the **indentation has no syntactic meaning** in C++. The start and end of blocks is marked by `{` and `}` alone. Blocks can be created inside other blocks. But blocks may not overlap partially. The usual rules of opening and closing of nested parentheses apply. \n",
+    "The top level block is always the body of a function.\n",
+    "\n",
+    "Although blocks are frequently used to organize code around `if` statements, loops etc., blocks can stand on their own. Anywhere in a function, \n",
+    "\n",
+    "One of the most interesting properties of blocks in C++ is that variables declared inside a block expire at the closing `}` of the block. This means, the any name-object link we made inside a block is completely invisible outside it, as if it never existed."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "brown-coalition",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Rocinante is approaching Tycho\n",
+      "4\t11\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(std::basic_ostream<char, std::char_traits<char> > &) @0x7f1de6a6fde0\n"
+      ]
+     },
+     "execution_count": 2,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "{\n",
+    "    string ship{\"Rocinante\"}, destination{\"Tycho\"};\n",
+    "    cout << ship << \" is approaching \" << destination << \"\\n\";\n",
+    "}\n",
+    "// First run this cell as it is. Then uncomment just the next line and try again.\n",
+    "// cout << ship << \"\\n\";\n",
+    "// You will see errors reported by the compiler, because the variable ship is not defined outside the block where it was introduced.\n",
+    "// Now, re-insert the comment markers // and uncomment the following two lines instead\n",
+    "int ship{4}, destination{11};\n",
+    "std::cout << ship << \"\\t\" << destination << \"\\n\";\n",
+    "// Since the variable names ship and destinations were not defined outside the block at the top, we were free to define and use\n",
+    "// them for any purpose we need! Here we created integers with those names."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "honey-aspect",
+   "metadata": {},
+   "source": [
+    "```c++\n",
+    "if (argc > 1) {\n",
+    "    auto N { stoi(argv[1]) }; // N is an integer\n",
+    "} else {\n",
+    "    string N { \"Navoo\" }; // N is a string\n",
+    "}\n",
+    "cout << N << \"\\n\"; // Error! N is not defined.\n",
+    "```\n",
+    "You can define any variables inside a block with any name which is not used to define another variable in that block. But that definition has no bearing on what goes on outside that block. Try the above!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "military-danger",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "{\n",
+    "    auto argc = 2;\n",
+    "if (argc > 1) {\n",
+    "    auto N { stoi(\"224\") }; // N is an integer\n",
+    "} else {\n",
+    "    string N { \"Navoo\" }; // N is a string\n",
+    "}\n",
+    "// cout << N << \"\\n\"; // Error! N is not defined.\n",
+    "// What (declarations) happens in a block, stays in that block\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "floating-sociology",
+   "metadata": {},
+   "source": [
+    "## Scope of a declaration\n",
+    "\n",
+    "Variables can have a finite well regulated lifetime, after which the name of the variable can be reused for something else, e.g., another variable of any type. A **scope** is \n",
+    "- for a variable declared in a block, the scope begins with its declaration and ends at the closing `}` of the block\n",
+    "- for a variable declared in the header of a for loop, its scope is the loop body\n",
+    "- for variables declared along with the condition in an `if` statement: both `if` and `else` part of the conditional branch\n",
+    "- for variables declared in the function header, the scope is the function body (later!)\n",
+    "\n",
+    "A variable declared in a scope exists from the point of declaration till the end of the scope. If the program exits the scope, the variable expires, and its name may be reused."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "humanitarian-carter",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1\n",
+      "1\n",
+      "2\n",
+      "3\n",
+      "5\n",
+      "8\n",
+      "13\n",
+      "21\n",
+      "34\n",
+      "55\n",
+      "89\n",
+      "144\n",
+      "233\n",
+      "377\n",
+      "610\n",
+      "987\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "int i = 0, j=1;\n",
+    "while (j < 1000) {\n",
+    "    // if (i > 0) cout << \"old value of sum = \" << sum << \"\\n\";\n",
+    "    // If you uncomment the above, it will be an error\n",
+    "    auto sum = i + j; // scope of sum begins here\n",
+    "    i = j;\n",
+    "    j = sum;\n",
+    "    cout << i << \"\\n\"; \n",
+    "} // scope of sum ends here. Even when we jump back into the loop, sum would be a free name"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "sixth-intention",
+   "metadata": {},
+   "source": [
+    "```c++\n",
+    "for (int i = 0; i < N; ++i) {\n",
+    "    //counter i defined only in this \"for\" loop.\n",
+    "}\n",
+    "double newval=0;\n",
+    "for (int i = 0; i < N; ++i) {\n",
+    "    // The counter i here is a different entity\n",
+    "    if (newval < 5) { // same newval as 3 lines earlier\n",
+    "        string fl{\"small.dat\"};\n",
+    "        // do something\n",
+    "    } // fl dies here!\n",
+    "    newval=...;\n",
+    "    cout << fl << ’\\n’; // Error! The name fl is not defined here!\n",
+    "}\n",
+    "int fl=42; // ok\n",
+    "if (auto f=filename; newval < 5) {// C++17\n",
+    "    // f is available here\n",
+    "} else {\n",
+    "    // f is also available here\n",
+    "}\n",
+    "```\n",
+    "Variables declared outside any limited scope are called \"global\" variables, and they live until the program itself ends execution. "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "stretch-bearing",
+   "metadata": {},
+   "source": [
+    "### Name visibility in nested blocks\n",
+    "\n",
+    "Any names visible in the program at the point we start a new block are visible throughout that block, unless *shadowed* by declarations in that block."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "id": "reduced-warehouse",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "line 3: 1\t2\t3\n",
+      "line 5: 1\t2\tumbrella\n",
+      "line 6: s3 has size 8\n",
+      "line 8: 1\t2\t3\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(std::basic_ostream<char, std::char_traits<char> > &) @0x7f1de6a6fde0\n"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "int s1{1}, s2{2}, s3{3};\n",
+    "if (s1 < s3) {\n",
+    "    // s1, s2 and s3 are visible here, because they were visible at the opening { of this block\n",
+    "    cout << \"line 3: \" << s1 << \"\\t\" << s2 << \"\\t\" << s3 << \"\\n\";\n",
+    "    std::string s3{\"umbrella\"}; // A new block-local s3 comes in and \"shadows\" the outside s3\n",
+    "    cout << \"line 5: \" << s1 << \"\\t\" << s2 << \"\\t\" << s3 << \"\\n\"; // s1, s2 from before, s3 from the block\n",
+    "    cout << \"line 6: \" << \"s3 has size \" << s3.size() << \"\\n\"; // every time you use s3 till the closing } of the block, you will see the new, block local s3\n",
+    "} // The s3 declared inside the block dies here. Shadow lifts!\n",
+    "cout << \"line 8: \" << s1 << \"\\t\" << s2 << \"\\t\" << s3 << \"\\n\";"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "focal-material",
+   "metadata": {},
+   "source": [
+    "## Namespaces\n",
+    "\n",
+    "So far, in some of our introductory notebooks, we have been able to print things by simply writing `cout << x`. This is because of the statement `using namespace std;` in the \"you will understand later\" cell at the start. Usually you would need to write `std::cout << x`. In order to understand how that works, we have to understand the concept of a `namespace` in C++. \n",
+    "\n",
+    "The following is a conversation I never had, but I could have had!\n",
+    "\n",
+    "### Imaginary conversation...\n",
+    "\n",
+    "A: \"Thomas Müller is in this building.\"\n",
+    "\n",
+    "B: \"The football player ?\"\n",
+    "\n",
+    "A: \"Yes, I guess, he plays football. Sometimes. Quite possibly.\"\n",
+    "\n",
+    "B: \"In the German national team ?\"\n",
+    "\n",
+    "A: \"No, not that one. I meant the scientist working in the computational science (CS) division at the Jülich Supercomputing Centre (JSC).\"\n",
+    "\n",
+    "B: \"So, you meant, JSC :: CS :: Thomas Müller !\"\n",
+    "\n",
+    "\n",
+    "- A **namespace** is a named context in which variables, functions etc. may be defined\n",
+    "- `::` is called the **scope resolution operator**\n",
+    "- The statement `using namespace blah` imports all the names in the namespace `blas` into the current scope\n",
+    "\n",
+    "```c++\n",
+    "// Somewhere in the header iostream\n",
+    "namespace std {\n",
+    "    ostream cout; // Definition of a variable called cout with the useful property that lets us write things on the terminal\n",
+    "    // << is an operator in C++, like +, -, *, /\n",
+    "    // When we use << with a variable of type ostream on the left and something else on the right,\n",
+    "    // that other thing gets written to the screen. ostream is a library provided class, and you will\n",
+    "    // see, we can control the behaviour of operators when class types are involved. Later!\n",
+    "    \n",
+    "    // The definition of the variable cout sits inside the namespace std\n",
+    "}\n",
+    "// In your program ...\n",
+    "#include <iostream>\n",
+    "// A variable called std::cout is now visible\n",
+    "auto main() -> int\n",
+    "{\n",
+    "    {\n",
+    "        using namespace std;\n",
+    "        // All names defined in the namespace std are visible. Therefore std::cout can now be\n",
+    "        // addressed by its plain name, cout\n",
+    "        cout << __func__ << \"\\n\";\n",
+    "    } // Visibility of the names imported by the using namespace declaration ends here!\n",
+    "    int cout = 0; // This cout is just an integer\n",
+    "    for (cout = 0; cout < 5; ++cout)\n",
+    "        std::cout << \"Counter = \" << cout << ’\\n’;\n",
+    "    // Above, plain cout is an integer,\n",
+    "    // but std::cout is an output stream\n",
+    "    // The syntax to refer to a name\n",
+    "    // defined inside a namespace is:\n",
+    "    // namespace_name::identifier_name\n",
+    "}\n",
+    "\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "stupid-madonna",
+   "metadata": {},
+   "source": [
+    "Let's explore namespaces by creating some on our own."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "retained-difference",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "#include <iostream>\n",
+    "#include <string>\n",
+    "namespace UnitedKingdom {\n",
+    "    std::string London{\"Big city\"};\n",
+    "}\n",
+    "namespace UnitedStates {\n",
+    "    std::string London{\"Small town in Kentucky\"};\n",
+    "}\n",
+    "using namespace UnitedKingdom;\n",
+    "\n",
+    "// You can not rerun this cell without restarting this kernel. That's why we isolated\n",
+    "// the namespace part to its own notebook."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "liable-sierra",
+   "metadata": {},
+   "source": [
+    "The reason why repeated execution of the above cells causes issues in the interpreter is that all definitions in a namespace are \"global\". Namespaces can not be declared in block scope. In a real C++ header or source file, you would put namespace definitions outside function bodies. Namespaces can also be reopened to add new definitions. That's why, once we execute the above cell, variables like `London` get defined, and those definitions last for the duration the kernel in this interpreter stays alive. When running it a second time, `cling` notices that we are trying to define, for example, another variable called `London` in the same namespace. Namespace variables being global, the previous definition is still active, and can not be replaced. And hence the error."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "id": "educational-effort",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Big city\n",
+      "Small town in Kentucky\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(std::basic_ostream<char, std::char_traits<char> > &) @0x7f2df7fdcde0\n"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "std::cout << London << '\\n';\n",
+    "std::cout << UnitedStates::London << '\\n';"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "italian-theology",
+   "metadata": {},
+   "source": [
+    "Let's reopen the `UnitedKingdom` namespace and add a new variable to it."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "id": "meaning-toronto",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "namespace UnitedKingdom {\n",
+    "    std::string Cambridge{\"University town\"};\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "id": "addressed-correspondence",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "University town\n",
+      "Big city\n",
+      "Small town in Kentucky\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(std::basic_ostream<char, std::char_traits<char> > &) @0x7f2df7fdcde0\n"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "std::cout << UnitedKingdom::Cambridge << \"\\n\" << UnitedKingdom::London << \"\\n\" << UnitedStates::London << \"\\n\";"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fresh-preserve",
+   "metadata": {},
+   "source": [
+    "The same name can appear in different namespaces without a \"name clash\". Only if we try to import multiple namespaces each defining the same symbol do we have a name clash:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "id": "heavy-frame",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 11,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "// If you uncomment the following lines and run this cell, you would have to restart the kernel\n",
+    "//using namespace UnitedStates;\n",
+    "//std::cout << London << \"\\n\";"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "coupled-radical",
+   "metadata": {},
+   "source": [
+    "Namespaces can be nested to arbitrary depth."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "id": "compatible-bobby",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "namespace UnitedStates {\n",
+    "    namespace KY {\n",
+    "        std::string London{\" in Kentucky\"};\n",
+    "    }\n",
+    "    namespace OH {\n",
+    "        std::string London{\" in Ohio\"};\n",
+    "    }\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "id": "deluxe-night",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      " in Ohio\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(std::basic_ostream<char, std::char_traits<char> > &) @0x7f2df7fdcde0\n"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "std::cout << UnitedStates::OH::London << \"\\n\";"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "adaptive-interstate",
+   "metadata": {},
+   "source": [
+    "Specifying multiple nested namespaces can get tidious, with long names followed by :: and more names. But it is possible to create shorthand aliases for long nested namespace names."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "id": "danish-cabin",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "input_line_17:3:6: error: no type named 'cout' in namespace 'std'\n",
+      "std::cout << \"London is \" << USOH::London << '\\n';\n",
+      "~~~~~^\n",
+      "input_line_17:3:11: error: expected unqualified-id\n",
+      "std::cout << \"London is \" << USOH::London << '\\n';\n",
+      "          ^\n"
+     ]
+    },
+    {
+     "ename": "ename",
+     "evalue": "evalue",
+     "output_type": "error",
+     "traceback": []
+    }
+   ],
+   "source": [
+    "#include <iostream>\n",
+    "namespace USOH = UnitedStates::OH;\n",
+    "std::cout << \"London is \" << USOH::London << '\\n';\n",
+    "// This is valid code, has been valid since C++11. But the cling interpreter does not support this.\n",
+    "// The error message you get is also meaningless. Observe the syntax above and use it."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "linear-sheet",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "C++17",
+   "language": "C++",
+   "name": "cling-cpp17"
+  },
+  "language_info": {
+   "codemirror_mode": "c++",
+   "file_extension": ".c++",
+   "mimetype": "text/x-c++src",
+   "name": "c++"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/Functions.ipynb b/notebooks/Functions.ipynb
new file mode 100644
index 0000000..2193263
--- /dev/null
+++ b/notebooks/Functions.ipynb
@@ -0,0 +1,1529 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "5430e0a6",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 1,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "#include <iostream>\n",
+    "#include <cmath>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "3ea21381",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 2,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "#pragma cling add_include_path(\"/p/project/training2213/local/include\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "437b9e73",
+   "metadata": {},
+   "source": [
+    "## Functions\n",
+    "\n",
+    "As the last topic for this notebook on fundamental concepts, let's examine functions. Unlike what we have been doing in this interpreted environment, all executable code like, `1 + 1`, `std::cout << whatever`, `for` loops, `if` statements ... all such code must be inside functions in C++. Only declarations of global variables, class and function definitions and other similar things can occur outside function bodies. In fact, function definitions **can not be inside bodies of other functions**.\n",
+    "\n",
+    "Functions are recipes for calculating zero or more outputs from zero or more inputs.\n",
+    "\n",
+    "```c++\n",
+    "auto func_name(double x) -> double\n",
+    "{\n",
+    "    if (x > 1.0 or x < -1.0) \n",
+    "        return 0;\n",
+    "    else \n",
+    "        return (1 - x) * (1 - x);\n",
+    "}\n",
+    "```\n",
+    "\n",
+    "Any conceptually important input->output mapping can be made into a function. The top line in the function definition above, called its header, makes the input->output connections clear. Function inputs go in the parentheses `()`, and the output is written to the right of the input: `(inputs) -> output`. The older function syntax, shared with \"C\" is written as follows:\n",
+    "```c++\n",
+    "double func_name(double x)\n",
+    "{\n",
+    "    // recipe\n",
+    "}\n",
+    "```\n",
+    "\n",
+    "This is still valid, and in this notebook it is the only working syntax for functions. But I consider the newer syntax with output to the right clearer and preferable. Outside this notebook, that syntax should be favoured.\n",
+    "\n",
+    "### Side effects\n",
+    "\n",
+    "Functions may also have side effects on the global state of the program.\n",
+    "\n",
+    "```c++\n",
+    "auto largest_squared_num = 0.;\n",
+    "auto sqr(double x) -> double\n",
+    "{\n",
+    "    x = x * x;\n",
+    "    if (x > largest_squared_num)\n",
+    "        largest_squared_num = x;\n",
+    "    return x;\n",
+    "}\n",
+    "```\n",
+    "\n",
+    "Every time we call the above function, there is a chance that we modify the global variable `largest_squared_num`. We can always look at the variable `largest_squared_num` to see the largest square calculated in the program so far. That value is not the \"result\" of the function, but it may change when we call `sqr`. That is called a side-effect. Any time you write something with `std::cout`, it is a side effect, because it changes the state of the global IO buffers. Side effects are sometimes necessary, or else we will not be able to write anything on the screen or in a file. Functions without any side-effects, strictly calculating an output from some inputs, are called \"pure\" functions. `func_name` above is a pure function. `sqr` above is not. Pure functions can be called simultaneously from any number of threads, and we can be confident that each of the calls will produce the right answer. If a function modifies global state, those modifications must be carefully orchestrated so that, multiple threads do not simultaneously modify a global variable, which can lead to incorrect or invalid states for those global variables.\n",
+    "\n",
+    "Using global constants does not modify global state, and hence does not have side effects.\n",
+    "\n",
+    "When a function is not meant to calculate and return any answer, its return type is written as `void`. Since `auto func(int i) -> void` looks somewhat awkward, we use the older syntax `void fun(int i)` for those functions. It helps distinguishing those \"procedures\" from other functions. A `void` returning function which is also pure, is simply some extra text. (no effects, no side-effects)\n",
+    "\n",
+    "If the formal parameter is an L-value reference, the function may change the value of the object used to initialize it. This is another kind of side effect. L-value reference parameters to a function can be considered **out**-parameters, or **in-out**-parameters.\n",
+    "\n",
+    "### Variable visibility\n",
+    "\n",
+    "The function bodies define a top level block scope. The only variables known in a function are\n",
+    "\n",
+    "    - those which are declared in the function\n",
+    "    - input parameters\n",
+    "    - global (namespace) scope variables\n",
+    "    \n",
+    "In particular, variables in the bodies of other functions are not available for use. The scoping rules, different control flow mechanisms you have learned so far can be used to write the recipe to calculate output values from inputs.\n",
+    "\n",
+    "Let's practice that!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0374a317",
+   "metadata": {},
+   "source": [
+    "### Exercise\n",
+    "\n",
+    "Write a function taking the distance between two particles and their masses as inputs, producing the Newtonian gravitational potential energy between them as the output. The Newtonian gravitational potential is given by $V(m_1, m_2, r) = -G\\frac{m_1 m_2}{r}$."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "626a2f85",
+   "metadata": {},
+   "source": [
+    "### Exercise\n",
+    "\n",
+    "We have a system of N particles so that their x, y, z positions and their masses are stored in `std::vector`s. Write a function to calculate the total gravitational potential energy of the system."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "44002173",
+   "metadata": {},
+   "source": [
+    "### Mental model for function calls"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5ba85507",
+   "metadata": {},
+   "source": [
+    "To write good functions, one has to understand a little bit about what happens when we use (call) a function. Whenever we call a function, the recipe in the function body is executed. Let's illustrate by taking an example function where we add up the elements of an input `vector`:\n",
+    "\n",
+    "```c++\n",
+    "auto addup(Something V) -> double\n",
+    "{\n",
+    "    double ans{};\n",
+    "    for (auto&& elem: V) ans += elem;\n",
+    "    return ans;\n",
+    "}\n",
+    "\n",
+    "auto elsewhere()\n",
+    "{\n",
+    "    std::vector masses{1., 1., 1.2, 1.4, 0.9, 1.5, 1.1 };\n",
+    "    std::vector charges{1.0, 1.0, 0.1, 0.1, 0.1, 0.1, 0.1};\n",
+    "    std::cout << \"Total mass = \" << addup(masses) << \"\\n\";\n",
+    "    std::cout << \"Total charge = \" << addup(masses) << \"\\n\";\n",
+    "}\n",
+    "\n",
+    "```\n",
+    "\n",
+    "What happens in the line where we call `addup(masses)` ? Somehow the recipe for adding up the elements must be executed with the elements of the vector `masses` and not the vector `charges`. Similarly when we call `addup(charges)` the exact same recipe will be executed, but now `V` representing the `charges` vector. \n",
+    "\n",
+    "The variable `V` in the function header is called, in other languages, a formal argument or a dummy argument. Before the recipe of the function is executed, the formal arguments are initialised using the corresponding values in the function call expression. Here is the crucial point: **this initialisation is exactly like a variable initialisation from an expression!** We are essentially replacing `addup(masses)` by the result of the following procedure:\n",
+    "\n",
+    "```c++\n",
+    "Something V{masses};\n",
+    "double ans{};\n",
+    "for (auto&& elem: V) ans += elem;\n",
+    "result = ans;\n",
+    "```\n",
+    "\n",
+    "This is why we spent such a long time discussing name stickers, duplicates and so on. Remember how we created duplicates ? To create a dupliate `vector` from a `vector`, you would write:\n",
+    "\n",
+    "```c++\n",
+    "std::vector<double> duplicate{original};\n",
+    "```\n",
+    "\n",
+    "If we substitute `Something` above with `std::vector<double>`, our pseudo-code recipe above would basically create a duplicate vector before adding its elements. Do we really need a duplicate vector to add the elements ?\n",
+    "\n",
+    "We learned how to create aliases. `std::vector<double>& alias{original};`. Aliases or references are extra name stickers attached to the same objects. If we substitute `Something` with `std::vector<double>&`, our pseudo-code recipe becomes,\n",
+    "\n",
+    "```c++\n",
+    "std::vector<double>& V{masses};\n",
+    "double ans{};\n",
+    "for (auto&& elem: V) ans += elem;\n",
+    "result = ans;\n",
+    "```\n",
+    "\n",
+    "`V` becomes another name for `masses` when we are evaluating `addup(masses)`, and for `charges` when we are evaluating `addup(charges)`! This is good. But we can do better! Since the purpose of the `addup` function is to give us the sum, it makes no sense that it should change the `masses` or `charges`. We can make the `V` a constant reference, i.e., a read-only alias, so that we can be sure, that the function does not tamper with the masses. Thus,\n",
+    "\n",
+    "```c++\n",
+    "auto addup(const std::vector<double>& V) -> double\n",
+    "{\n",
+    "    double ans{};\n",
+    "    for (auto&& elem: V) ans += elem;\n",
+    "    return ans;\n",
+    "}\n",
+    "```\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "ef0ac830",
+   "metadata": {},
+   "source": [
+    "### Quiz:\n",
+    "\n",
+    "Consider the very simple function below. Why does one of the attempts to use it work but the next one does not ?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "bb0516a2",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "int f1(int& i)\n",
+    "{\n",
+    "    return i + 2;\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "4cc79b0b",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "4002\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "{\n",
+    "    int N{4000};\n",
+    "    std::cout << f1(N) << \"\\n\"; // this works\n",
+    "    // std::cout << f1(4000) << \"\\n\"; // this does not. Why ?\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fa72103a",
+   "metadata": {},
+   "source": [
+    "It is always possible to understand what works and does not work based on the mental picture discussed earlier. Function call involves initialisation of the formal function parameters using the call expression. We can not initialise a non-constant L-value reference (`int&` above) from a pure R-value (`4000`). Since a constant reference can not be used on the left side of an assignment, we can create such entites from pure values like `4000`.  "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "id": "74bdf8ec",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "const int& i{4000};"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a0e62ca4",
+   "metadata": {},
+   "source": [
+    "Therefore, a function declared in terms of a `const` reference can accept normal names as well as values as inputs."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "id": "a59a60b0",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "int f2(const int&i)\n",
+    "{\n",
+    "    return i + 2;\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "a73c5971",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "4002\n",
+      "4002\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "{\n",
+    "    int N{4000};\n",
+    "    std::cout << f2(N) << \"\\n\";\n",
+    "    std::cout << f2(4000) << \"\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "07ffaf77",
+   "metadata": {},
+   "source": [
+    "### Quiz:\n",
+    "\n",
+    "Why does the `cout` in the loop below execute 10 times, even if we call the increment function in the loop ?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "id": "5d8a8feb",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "void increment(int i)\n",
+    "{\n",
+    "    i = i + 1;\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "id": "bc01b57f",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0\n",
+      "1\n",
+      "2\n",
+      "3\n",
+      "4\n",
+      "5\n",
+      "6\n",
+      "7\n",
+      "8\n",
+      "9\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "for (auto i = 0; i < 10; ++i) {\n",
+    "    std::cout << i << \"\\n\";\n",
+    "    increment(i);\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8aa081a3",
+   "metadata": {},
+   "source": [
+    "Using our mental model of function calls, the `increment` function looks like this:\n",
+    "\n",
+    "```c++\n",
+    "int i_duplicate{i_original};\n",
+    "i_duplicate = i_duplicate + 1;\n",
+    "```\n",
+    "\n",
+    "As you can see, we are never touching the `i_original`, from inside the loop, inside the function. So, that `i` only gets incremented in the `for` loop. \n",
+    "\n",
+    "`TypeName varname{initialier}` *always* creates a new object, whether the initializer is a pure value, like `5` or the name of another variable, like `i`. That's what we arranged for, when we wrote our function input parameter as `int i`. \n",
+    "\n",
+    "How would you change the increment function so that it does not create a duplicate, but works on the same object that we pass it when calling the function ? Write a **different function with a different name** and test! If you do not give the function a different name, we get into \"ambiguous\" definitions, and the fascinating topic of function overloading in C++ (next section)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e8c1dd60",
+   "metadata": {},
+   "source": [
+    "## Function overloading\n",
+    "\n",
+    "It is possible to have multiple functions of the same human readable name, as long as they can be distinguished by the types of the input parameters.\n",
+    "\n",
+    "```c++\n",
+    "auto power(double x, int i) -> double\n",
+    "{\n",
+    "    if (i == 0) return 1.;\n",
+    "    bool inv = (i < 0);\n",
+    "    auto ans = 1.;\n",
+    "    i = std::abs(i);\n",
+    "    for (auto j = 0; j < i; ++j) ans *= x;\n",
+    "    if (inv) ans = 1.0/ans;\n",
+    "    return ans;\n",
+    "}\n",
+    "\n",
+    "auto power(double x, double y) -> double\n",
+    "{\n",
+    "    return std::exp(y * std::log(x));\n",
+    "}\n",
+    "\n",
+    "void elsewhere()\n",
+    "{\n",
+    "    std::cout << power(3.14, 4) << \"\\n\"; // calls first version\n",
+    "    std::cout << power(3.14, 4.) << \"\\n\"; // calls second version\n",
+    "}\n",
+    "```\n",
+    "\n",
+    "Let's see that in action, and discuss."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "id": "3a1a2aa8",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "double power(double x, int i)\n",
+    "{\n",
+    "    std::cout << \"Calculating integer power \" << i << \" of \" << x << \"\\n\";\n",
+    "    if (i == 0) return 1.;\n",
+    "    bool inv = (i < 0);\n",
+    "    auto ans = 1.;\n",
+    "    i = std::abs(i);\n",
+    "    for (auto j = 0; j < i; ++j) ans *= x;\n",
+    "    if (inv) ans = 1.0/ans;\n",
+    "    return ans;\n",
+    "}\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "id": "b68c8550",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 11,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "double power(double x, double y)\n",
+    "{\n",
+    "    std::cout << \"Calculating floating point power \" << y << \" of \" << x << \"\\n\";\n",
+    "    if (x < 0.) throw std::runtime_error{\"Bad negative input for non-integral power.\" };\n",
+    "    return std::exp(y * std::log(x));\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "id": "919888ee",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Calculating floating point power 4 of 3.14\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 97.211712\n"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, 4.0);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "id": "76430f6d",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Calculating integer power 4 of 3.14\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 97.211712\n"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, 4);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "37d3c1ce",
+   "metadata": {},
+   "source": [
+    "We didn't have to invent different names like `power_double_int` and `power_double_double` for these functions. This is because that is conceptually what the compiler is doing for us! To the C++ compiler, the name of a function is not just the name by which you see it, but it is that name + the types of all the inputs to the function. Therefore, as far as the compiler is concerned, we declared two completely different functions above. How does the compiler know which one to invoke when we write an expression like `power(a, b)` ?\n",
+    "\n",
+    "Even at the call site, if `a` is a double and `b` is an integer, the compiler sees it as an attempt to call `power_double_int`. The existence of the other function does not matter. If `b` is a double, it is again, clear to the compiler! You want to call `power_double_double`, and the compiler knows what that is!\n",
+    "\n",
+    "`power` above is said to be an overloaded function with two overloads. The collection of all functions sharing the same human readable name and different input parameter types is called an \"overload set\".\n",
+    "\n",
+    "How much time does this kind of overloading cost when the program is running ?\n",
+    "\n",
+    "<h1>0.0 femtoseconds!</h1>\n",
+    "\n",
+    "The function overloading mechanism is a purely compile time process. In any C++ program, the compiler resolves the entire possible set of function calls ahead of time (Let's discuss *virtual* function calls in due time along with C++ classes). This decision, whether to call one or the other version of `power` is not happening at program execution time.\n",
+    "\n",
+    "It is important that the compiler is able to distinguish between the overloads. You can not have two versions of `power` each taking a `double` and `int`, but one handling positive integers and the other handling negative integrs. You might think that `double` and `int` are, of course, easy to tell apart. How similar can the type of the second input parameter be and still be used to overload `power` ?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "id": "01294e05",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "double power(double x, short i)\n",
+    "{\n",
+    "    std::cout << \"A possible third implementation of the same function.\\n\";\n",
+    "    return 0.; // We are just focussing on overload resolution right now.\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "id": "2bf951cf",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Calculating integer power 2 of 3.14\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 9.8596000\n"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, 2);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "id": "e902b270",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A possible third implementation of the same function.\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 0.0000000\n"
+      ]
+     },
+     "execution_count": 16,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, short{2}); // There is no literal suffix for short."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "id": "d9121962",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "double power(double x, long i)\n",
+    "{\n",
+    "    std::cout << \"double to the power long\\n\";\n",
+    "    return 0.; // Just focussing on overload resolution...\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "id": "7d3db026",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "double to the power long\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 0.0000000\n"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, 2L); // There is a literal suffix for long"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "id": "fc9ac67c",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "double power(double x, unsigned long i)\n",
+    "{\n",
+    "    std::cout << \"double to the power unsigned long\\n\";\n",
+    "    return 0.; // Just focussing on overload resolution...\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "id": "39faaaf8",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "double to the power unsigned long\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 0.0000000\n"
+      ]
+     },
+     "execution_count": 20,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, 2UL);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "id": "67864b73",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Calculating floating point power 2 of 3.14\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 9.8596000\n"
+      ]
+     },
+     "execution_count": 21,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, 2.);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "id": "8f4d0059",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Calculating integer power 8 of 3.14\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 9450.1170\n"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, 8);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "id": "5fcecf52",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A possible third implementation of the same function.\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 0.0000000\n"
+      ]
+     },
+     "execution_count": 23,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, short{8});"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "id": "183bf148",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "double to the power long\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 0.0000000\n"
+      ]
+     },
+     "execution_count": 24,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(3.14, 8L);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "id": "41595dff",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Calculating integer power 2 of 3.14\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 9.8596000\n"
+      ]
+     },
+     "execution_count": 25,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "char c{2};\n",
+    "power(3.14, c);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "894dc241",
+   "metadata": {},
+   "source": [
+    "Above, we did not write a version of the overload for the `char` type. In this case, the compiler tries \"integer promotion\" to promote our `char` input into an `int` and uses the `int` version. All shorter than 32 bit integers are promoted to the \"natural\" 32 bit integers on current implementations."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "id": "62ad7ce2",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Calculating floating point power 0.77 of 3.14\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(double) 2.4134362\n"
+      ]
+     },
+     "execution_count": 26,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "double p{0.77};\n",
+    "power(3.14, p);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "15c1f21c",
+   "metadata": {},
+   "source": [
+    "Now let's examine overloading, but this time with functions taking references as formal parameters."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "id": "feb3cd48",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 27,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "void expt(double& x)\n",
+    "{\n",
+    "    std::cout << \"Version accepting mutable L-value reference\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "id": "bb457ada",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 28,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "void expt(const double& x)\n",
+    "{\n",
+    "    std::cout << \"Version accepting constant L-value reference\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "id": "0e404eae",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Version accepting constant L-value reference\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(void) @0x7f226d7f8dc0\n"
+      ]
+     },
+     "execution_count": 29,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "expt(0.);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "id": "77fb5e56",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 30,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "double x = 9.8;"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "id": "3c72431d",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Version accepting mutable L-value reference\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(void) nullptr\n"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "expt(x);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "id": "77a82bde",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Memory address of the object for x : 139786145235008\n",
+      "Memory address of the object for y : 139786145235008\n",
+      "Memory address of the object for z : 139786145235008\n",
+      "Version accepting mutable L-value reference\n",
+      "Version accepting constant L-value reference\n",
+      "Version accepting mutable L-value reference\n",
+      "Version accepting constant L-value reference\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(void) @0x7f226d7f8dc0\n"
+      ]
+     },
+     "execution_count": 32,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "const double& y{x};\n",
+    "double& z{x};\n",
+    "std::cout << \"Memory address of the object for x : \" << (size_t)std::addressof(x) << \"\\n\"; \n",
+    "std::cout << \"Memory address of the object for y : \" << (size_t)std::addressof(y) << \"\\n\"; \n",
+    "std::cout << \"Memory address of the object for z : \" << (size_t)std::addressof(z) << \"\\n\";\n",
+    "expt(x);\n",
+    "expt(y);\n",
+    "expt(z);\n",
+    "expt(z + y);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b8ba1a1a",
+   "metadata": {},
+   "source": [
+    "As you can see, we can have two different versions of the `expt` function, one accepting a normal, mutable, L-value reference, and another constant L-value reference. When we call the function, depending on the nature of the expression used to call the function, one or the other version is called. Notice that the identifiers `x`, `y` and `z` all identify the same entity in the computer's memory. But one of them, `y` is a read-only identifier. When calling `expt`, the version invoked is based on whether we have a mutable identifier or an immutable entity in the argument at the call site."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "id": "4f1f7a67",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 33,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "void expt2(double& x)\n",
+    "{\n",
+    "    std::cout << \"Version accepting mutable L-value reference\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "id": "8297bbc9",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 34,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "void expt2(const double& x)\n",
+    "{\n",
+    "    std::cout << \"Version accepting constant L-value reference\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "id": "5e00a08a",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 35,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "void expt2(double x)\n",
+    "{\n",
+    "    std::cout << \"Version where the formal argument is a value\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "id": "b4d15693",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "input_line_39:2:2: error: call to 'expt2' is ambiguous\n",
+      " expt2(3.0);\n",
+      " ^~~~~\n",
+      "input_line_37:1:6: note: candidate function\n",
+      "void expt2(const double& x)\n",
+      "     ^\n",
+      "input_line_38:1:6: note: candidate function\n",
+      "void expt2(double x)\n",
+      "     ^\n"
+     ]
+    },
+    {
+     "ename": "ename",
+     "evalue": "evalue",
+     "output_type": "error",
+     "traceback": []
+    }
+   ],
+   "source": [
+    "expt2(3.0);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "id": "74028319",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "input_line_40:2:2: error: call to 'expt2' is ambiguous\n",
+      " expt2(x);\n",
+      " ^~~~~\n",
+      "input_line_36:1:6: note: candidate function\n",
+      "void expt2(double& x)\n",
+      "     ^\n",
+      "input_line_37:1:6: note: candidate function\n",
+      "void expt2(const double& x)\n",
+      "     ^\n",
+      "input_line_38:1:6: note: candidate function\n",
+      "void expt2(double x)\n",
+      "     ^\n"
+     ]
+    },
+    {
+     "ename": "ename",
+     "evalue": "evalue",
+     "output_type": "error",
+     "traceback": []
+    }
+   ],
+   "source": [
+    "expt2(x);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "557ed962",
+   "metadata": {},
+   "source": [
+    "As you can see, having a version with a value and another with a reference leads to ambiguities. The compiler can not distinguish between a pure value and a constant reference at the call site. Avoid overloading between plain types and references."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0419be43",
+   "metadata": {},
+   "source": [
+    "## Recursion\n",
+    "\n",
+    "Remember the self-referencial definition of the factorial function in mathematics ? \n",
+    "\n",
+    "$$\n",
+    "N! = \\left\\{\n",
+    "    \\begin{array}\\\\\n",
+    "        N\\times (N-1)! & \\mbox{if } \\ N > \\mathbf{1} \\\\\n",
+    "        1 & \\mbox{if } \\ N = \\mathbf{0}\\,or\\,\\mathbf{1} \n",
+    "    \\end{array}\n",
+    "\\right.\n",
+    "$$\n",
+    "\n",
+    "The exact same thing can be expressed in a C++ function (this is a syntax explanation. I am not recommending writing factorial this way!).\n",
+    "\n",
+    "```c++\n",
+    "auto factorial(unsigned int N) -> unsigned int\n",
+    "{\n",
+    "    return (N > 1U) ? N * factorial(N - 1U) : 1U;\n",
+    "}\n",
+    "```\n",
+    "We used the ternary operator to compactly express the following:\n",
+    "\n",
+    "```c++\n",
+    "if (N > 1U)\n",
+    "    return N * factorial(N - 1U);\n",
+    "else\n",
+    "    return 1U;\n",
+    "```\n",
+    "\n",
+    "This type of expression, when a function calls itself from its own body, is called recursion. Recursive functions can sometimes be used to express complex tasks, such as tree processing, elegantly and compactly. But they also illustrate an important point: local variables as well as formal arguments of a function are private to a particular call. I refer you to the section 2.2.4.1 (\"Whiteboard stack\") for a more extended discussion. Right now, let's just rig our factorial function so that we can see this: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "id": "11c4fe1a",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 38,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "unsigned int factorial(unsigned int N)\n",
+    "{\n",
+    "    std::cout << \"Evaluating factorial of \" << N << \"\\tParameter stored at address \" << (size_t)(&N) <<\"\\n\";\n",
+    "    if (N <= 1U) {\n",
+    "        std::cout << \"No need for recursive calls. Returning 1\\n\";\n",
+    "        return 1U;\n",
+    "    } else {\n",
+    "        std::cout << \"Starting recursive call from level \" << N << \"\\n\";\n",
+    "        unsigned int rest = factorial(N-1);\n",
+    "        std::cout << \"At level N = \" << N << \", with factorial of the rest = \" \n",
+    "            << rest << \" stored at \" << &rest << \"\\n\";\n",
+    "        return N * rest;\n",
+    "    }\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "id": "59121ac6",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Evaluating factorial of 4\tParameter stored at address 139785842691624\n",
+      "Starting recursive call from level 4\n",
+      "Evaluating factorial of 3\tParameter stored at address 139785842691576\n",
+      "Starting recursive call from level 3\n",
+      "Evaluating factorial of 2\tParameter stored at address 139785842691528\n",
+      "Starting recursive call from level 2\n",
+      "Evaluating factorial of 1\tParameter stored at address 139785842691480\n",
+      "No need for recursive calls. Returning 1\n",
+      "At level N = 2, with factorial of the rest = 1 stored at 0x7f226d7f8dc4\n",
+      "At level N = 3, with factorial of the rest = 2 stored at 0x7f226d7f8df4\n",
+      "At level N = 4, with factorial of the rest = 6 stored at 0x7f226d7f8e24\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(unsigned int) 24\n"
+      ]
+     },
+     "execution_count": 39,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "factorial(4);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0987873a",
+   "metadata": {},
+   "source": [
+    "Notice how for each level of recursion, the parameter values were stored at different locations. Each **call** to a function has its own separate working area to store its formal parameters, local variables etc. This area is called the \"stack frame\" of a function. When a function returns, its stack frame is reused for subsequent function calls. This is why there is no danger that the local variable `rest` for one level of the factorial will be erased or overwirtten by the calculation from another level."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "ed2541fc",
+   "metadata": {},
+   "source": [
+    "## Multiple output values\n",
+    "\n",
+    "Syntactically, a C++ function has a single return type. There can be multiple return statements as in the `factorial` function above, but they must all return the same type of object. What if we need to return more than one output from a function ? There are many ways of doing that:\n",
+    "\n",
+    "    - We can use non-constant L-value reference parameters, and assign to those parameters in the function\n",
+    "    - The function can return a `tuple` containing those different types\n",
+    "    - Multiple outputs can be bundled together in a `struct` or `class`\n",
+    "    \n",
+    "Let's illustrate that using a simple integer division function. We divide two integer inputs. The answer we seek are both quotient and remainder. \n",
+    "\n",
+    "In the first approach, our function could look like this:\n",
+    "\n",
+    "```c++\n",
+    "auto integer_division(int L, int R, int& q, int& r) -> int\n",
+    "{\n",
+    "    q = L / R;\n",
+    "    r = L % R;\n",
+    "    return q;\n",
+    "}\n",
+    "```\n",
+    "This approach has been in use for a long time. To use this, we have to do something like this:\n",
+    "\n",
+    "```c++\n",
+    "void elsewhere()\n",
+    "{\n",
+    "    int num1{somevalue}, num2{anothervalue};\n",
+    "    int quotvar, remvar;\n",
+    "    integer_division(num1, num2, quotvar, remvar);\n",
+    "    std::cout << \"Quotient = \" << quotvar << \", remainder = \" << remvar << \"\\n\";\n",
+    "}\n",
+    "```\n",
+    "\n",
+    "The L-value reference parameters ensure that the assignments to `q` and `r` done inside the function are performed on `quotvar` and `remvar`. It works. But it obscures the distinction between the inputs and outputs for the function. It is easy to get confused about which arguments are inputs and which are outputs. The second approach looks like this:\n",
+    "\n",
+    "```c++\n",
+    "auto integer_division(int L, int R) -> std::tuple<int, int>\n",
+    "{\n",
+    "    return std::make_tuple(L / R, L % R);\n",
+    "}\n",
+    "\n",
+    "void elsewhere()\n",
+    "{\n",
+    "    int num1{somevalue}, num2{anothervalue};\n",
+    "    auto [quotvar, remvar] = integer_division(num1, num2);\n",
+    "    std::cout << \"Quotient = \" << quotvar << \", remainder = \" << remvar << \"\\n\";\n",
+    "}\n",
+    "```\n",
+    "\n",
+    "There is no confusion regarding the inputs and outputs for this function. The output of the function is a tuple, but we can kind of \"unpack\" it using the notation shown. If we did not use the structured binding notation of `auto [name1, name2 ...] = tuple`, we will receive a tuple as the output. One can access the components of the tuple, but the notation is not as elegant:\n",
+    "\n",
+    "```c++\n",
+    "void elsewhere()\n",
+    "{\n",
+    "    int num1{somevalue}, num2{anothervalue};\n",
+    "    auto res = integer_division(num1, num2);\n",
+    "    std::cout << \"Quotient = \" << std::get<0>(res) << \", remainder = \" << std::get<1>(res) << \"\\n\";\n",
+    "}\n",
+    "```\n",
+    "\n",
+    "The third approach needs us to define a `struct` to staple together the values we want to receive as output.\n",
+    "\n",
+    "```c++\n",
+    "struct div_result_type\n",
+    "{\n",
+    "    int quotient;\n",
+    "    int remainder;\n",
+    "};\n",
+    "```\n",
+    "\n",
+    "`div_result_type` then becomes a new data type. One can create variables of this type. Each of those variables will have a \"member\" called quotient and another member called remainder. The members can be accessed using a dot notation :\n",
+    "```c++\n",
+    "div_result_type res{v1, v2};\n",
+    "// ...\n",
+    "if (res.quotient > res.remainder)\n",
+    "    do_something();\n",
+    "```\n",
+    "\n",
+    "Our `integer_division` function can then be written as:\n",
+    "\n",
+    "```c++\n",
+    "auto integer_division(int L, int R) -> div_result_type\n",
+    "{\n",
+    "    return { L / R, L % R };\n",
+    "}\n",
+    "\n",
+    "void elsewhere()\n",
+    "{\n",
+    "    int num1{somevalue}, num2{anothervalue};\n",
+    "    auto res = integer_division(num1, num2);\n",
+    "    std::cout << \"Quotient = \" << res.quotient << \", remainder = \" << res.remainder << \"\\n\";\n",
+    "    // alternatively\n",
+    "    auto [q, r] = integer_division(num1, num2);\n",
+    "    std::cout << \"Quotient = \" << q << \", remainder = \" << r << \"\\n\";\n",
+    "}\n",
+    "\n",
+    "```\n",
+    "\n",
+    "This third approach involves one extra step when writing the function: creation of the `struct` representing the output type. It can be used with a structured binding declaration like a `tuple`. But there is a subtle advantage. With the tuple, we have to look at the code to see which component is the quotient and which one is the remainder. The fields of a tuple are simply \"first field\", \"second field\" ... They have no names. The implementer of the function can not indicate their intent about which field is what. One has to rely on \"documentation\": one of the most error prone ways known to mankind to determine the purpose of tuple components! In the `struct` approach, there can be descriptive names, so that the meaning of the fields is clear.\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5b5ed59d",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "C++17",
+   "language": "C++",
+   "name": "cling-cpp17"
+  },
+  "language_info": {
+   "codemirror_mode": "c++",
+   "file_extension": ".c++",
+   "mimetype": "text/x-c++src",
+   "name": "c++"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/Fundamentals_1.ipynb b/notebooks/Fundamentals_1.ipynb
new file mode 100644
index 0000000..56866fb
--- /dev/null
+++ b/notebooks/Fundamentals_1.ipynb
@@ -0,0 +1,720 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Getting started with C++ using Jupyter notebook: Part 1\n",
+    "\n",
+    "This notebook will guide you through the initial steps for an introduction to C++. \n",
+    "Usually, C++ programs have to be \"compiled\" and then the compiled programs can be executed. For educational purposes, the instant feedback one gets in *interpreted* languages like Python is often considered \"easier\". There have been a few attempts to create interpreters for C++, which execute C++ programs line by line without having to compile it first. Cling is such an interpreter. There are Jupyter notebook kernels using the cling interpreter, and we are going to use one of them occasionally in this course, when it fits the purpose.\n",
+    "\n",
+    "Some caveats though:\n",
+    "\n",
+    "- C++ is a compiled language. To make it work in an intrepreter, additional rules are required, which are outside standard C++ language rules. Learning to structure C++ programs to suit the interpreter will impose an unnatural organisation, outside what is considered best practice in the developer community.\n",
+    "- cling is currently version 0.9. It works for some straight forward code in C++, but it's C++ coverage is NOT EVEN VAGUELY complete. A failure of cling to understand a piece of code does not necessarily mean the syntax is incorrect. Reason with what you know about C++. Use the real clang compiler. And while in this course, ask me!\n",
+    "- The Cling version on JupyterHub JSC is based on LLVM version 9.0, and the current LLVM version is 14.0. Many newer language features are simply unknown to the current version of cling. In particular, C++20 features. Because C++20 is by and large backwards compatible with C++17, we can use this notebook to learn about a subset of features.\n",
+    "- It is necessary to restart cling based Jupyter kernels often. Quite often it is because of inadequate language support. For instance, standard input does not work in Jupyter-cling, i.e., the C++ code can not ask the user for input and then process what the user types. Such things are trivial in normal C++, but not inside this notebook. We will skip anything that needs standard input in our notebooks.\n",
+    "\n",
+    "That said, to test a single line of code, the interpreter provides a very practical shortcut over writing a full program and going through the write - compile - run cycle. While learning, we need a lot of really small programs, and we will use this Jupyter notebook with xeus-cling kernel to illustrate syntax when possible.\n",
+    "\n",
+    "Each \"cell\" in this notebook contains either some text I wrote or a little bit of code. To \"execute\" a cell, you press Shift+Enter on your keyboard. Use the Help menu above to find out about keyboard shortcuts for Jupyter notebook. This first exercise session of the course is mostly intended as \"self study\" with the help of this notebook. Insert new cells using the insert menu above. Either type some code to test something in the new cells, or make it into a \"markdown\" cell by typing Esc+m. You can then type your own notes along side the material given. Ask if you need anything explained!\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#pragma cling add_include_path(\"/p/project/training2213/local/include\")\n",
+    "// Hopefully, you have read the introductory chapters in the course book and understand\n",
+    "// the purpose of the include statements. The specific include files we are using here\n",
+    "// will be explained later.\n",
+    "\n",
+    "// The contents of this cell are to set up this notebook. You don't need to understand\n",
+    "// how this works right now. Run this and move on!\n",
+    "#include <iostream>\n",
+    "#include <type_traits>\n",
+    "#include <string>\n",
+    "#include <vector>\n",
+    "#include <map>\n",
+    "#include <cmath>\n",
+    "#include <algorithm>\n",
+    "#include <typeinfo>\n",
+    "using namespace std;\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "If you are running this notebook on our JupyterJSC Hub, please run the following as it is. Otherwise, you have to adjust the include path to the location on your system where headers for software such as boost are stored. **Run only one of the following cells. If the first one works, leave the second one alone. If not, uncomment the code in the second cell and it.** "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <boost/type_index.hpp>\n",
+    "template <class T>\n",
+    "void typeof(T&& t) {\n",
+    "    std::cout << \"Type name: \" << boost::typeindex::type_id_with_cvr<T>().pretty_name() << \"\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// template <class T>\n",
+    "// void typeof(T&& t) {\n",
+    "//    std::cout << \"Type name: \" << typeid(t).name() << \"\\n\";\n",
+    "//}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## \"Hello, world!\" in C++\n",
+    "\n",
+    "```c++\n",
+    "cout << \"Hello, world!\\n\";\n",
+    "```\n",
+    "To write something to the screen (standard output) in a C++ program, you say `std::cout << something` or, if you are already using the `std` namespace (more on that in a bit), you can say `cout << something` as above. Try it below! "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "using namespace std;\n",
+    "cout << \"Hello, world!\\n\";"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Lesson not-to-learn:\n",
+    "Notice that if you run the cell above without the semi-colon `;` at the end, no error is reported. That is non-standard behaviour only accepted in this interpreted environment. **All C++ statements end in a semi-colon**. The additional rule that the `cling` interpreter uses, which allows skipping the last semi-colon is this:\n",
+    "\n",
+    "    - if the final semi-colon in a cell is missing, print the value of the expression\n",
+    "\n",
+    "The rule makes no sense outside the interpreter. Since we are in the interpreter right now, we might as well use it below to invoke this \"auto-print\" behaviour, but remember: that **will not work in a real C++ program!** When you need to write something on the screen, use `cout`. "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To write more than one thing, you can \"chain\" your outputs together like this:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cout << \"Cube of 13 is \" << 13 * 13 * 13 << \",\\n and for 14 that is \" << 14 * 14 * 14 << \"\\n\";"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Observe where the output goes to a new line above. `cout` does not automatically print a line. You start writing in a new line when you explicitly write the newline character `'\\n'`. Can you change the code above so that all of the text is in one line ? How about starting a new line where we did, but making the 'C' and the 'a' in the two lines aligned ?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Values"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The following few cells should be fairly obvious. Just execute them, and verify that you understand the output. Is the output always what you expect ?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1 + 2"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "If you got an error above (cling gets all confused many times!), please first try to restart the notebook and run the cells again. If the problem does not go away, ask me."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1 - 2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1 * 2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1 / 2"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The above expression sometimes confuses some people, especially if coming from python. In python, the answer will be 0.5. Here, since 1 and 2 are both integers, we perform integer arithmetic, i.e. division with a remainder. What you got was the quotient, which really is 0. To get the remainder, run the next cell:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1 % 2"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now, let's repeat that, but this time, using \"unsigned integer\" values. Unsigned integers are non-negative integers. To write unsigned integer literal values, you put a 'U' character after the integer value."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1U + 2U"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1U - 2U"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1U * 2U"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1U / 2U"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1U % 2U"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Here, the unexpected value was probably `1U - 2U`. This has the value $4294967295 = 2^{32}-1$. Integers and unsigned integers are commonly represented by 32 binary bits. Unsigned integers have modular arithmetic between $0$ and $2^{32} - 1$, like a clock, but with $4294967296$ hours instead of $24$. If you keep decreasing beyond the lower bound, you appear at the other end. If you keep increasing past the maximum, you start from the left side again. Observe:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "4294967295U + 1U"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "4294967295U + 2U"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now let's calculate with floating point decimal numbers. Decimal double precision floating point numbers are written using ordinary decimal point notation. If the fractional part is all $0$, you don't need to write it. So, `1.0` can be written as `1.` etc.:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1. + 2."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1. - 2."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1. * 2."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "1. / 2."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The above should look fairly straightforward. Since we are dealing with decimal numbers, we are not using integer arithmetic, and we get $0.5$ when we divide $1.$ by $2.$. Now, let me say it one more time that the above lines are not full C++ statements, but mere expressions. If you want to do the operations above and print the results, you would do something like this:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cout << 1. / 2. << \"\\n\";"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "For the computer, $1.$ above is not simply $1$ with a dot attached. In the second chapter of the companion book for this course, we describe the binary representation of floating point numbers. The example program to find out the binary bits of a number, `binform.cc` requires more C++ than what this version of `cling` supports. But a version compatible with C++17 is available to you in the course set up. You can include that file and get bit representations of numbers as follows:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <binform17.hh>\n",
+    "using namespace cxx2022;\n",
+    "// The header declares functions in the namespace 2022."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "showbits(33);\n",
+    "showbits(33.0);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now, try running that function for a few numbers: (suggestions) 1, 1.0, 2, 2.5, -1.3333, -1.0, 4, 4.0, 3, 3.0, ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "showbits(3.1415927F)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Types, values, variables and declarations\n",
+    "\n",
+    "In computer memory, all information is stored in *bits*, which can be either 0 or 1.\n",
+    "Depending on the \"type\" you associate with a bunch of bits, they may represent different values. For example, consider these bits ...\n",
+    "\n",
+    "```\n",
+    " 0100 0000 0100 1001 0000 1111 1101 1011\n",
+    "```\n",
+    "\n",
+    "If you decide that they represent a 32 bit integer, they represent the number **1078530011**. If you say it is a 32-bit floating point number (decimal number), the exact same bits represent the number **3.1415927**. It's not possible to tell what kind of value is stored in a block of memory by staring hard at the bits. The programming language associates \"types\" with stored (and literal) values, which define the number of bits in a value of that type and the rules governing the interpretation of those bits (among other things).\n",
+    "\n",
+    "There are a few types built into the C++ language, called imaginatively, \"built-in types\". These are,\n",
+    "\n",
+    "    - `int`, `unsigned int` : (typically) 32-bit signed and unsigned integers\n",
+    "    - `long`, `unsigned long` : (typically) 64-bit signed and unsigned integers\n",
+    "    - `short`, `unsigned short`: (typically) 16-bit signed and unsigned integers\n",
+    "    - `char`, `unsigned char`: 8-bit signed and unsigned integers, interpreted as characters\n",
+    "    - `float` : 32-bit floating point numbers (no \"unsigned float\"!)\n",
+    "    - `double` : 64-bit floating point numbers (no \"unsigned double\"!)\n",
+    "    - `bool` : A type storing true or false\n",
+    "    \n",
+    "Besides these built-in types, C++ provides mechanisms for programmers to create new data types whose behaviour (what operations make sense on that type, what happens when you add, subtract etc. etc.) is programmable. User defined data types are created using C++ **class**es (or **struct**s), which will be discussed in detail later in the course. The C++ standard library introduces a lot of very useful classes. These are written using the *same mechanisms* as those which are available to you to create your classes. The standard library classes are, by and large, user defined types, and will be called so in the following.\n",
+    "\n",
+    "The important takeaway from all this is that in order to know how to make meaningful calculations with a sequence of bits, the computer needs to know what type we associate with those bits. In other words, to interpret a \"value\" from a sequence of bits, the bit representation must be combined with type information. An \"object\" is a concrete example of a sequence of bits representing a value of a certain type.\n",
+    "\n",
+    "Like lots of programming languages, you can create \"named\" objects, or  *variables*, to store and reuse values.  *variables* are convenient stores of useful values so that we can use them in subsequent work, change the stored values etc. If you ever owned an old fashioned calculator, where you could memorize some calculated values and restore them later, that's roughly the role of a variable.\n",
+    "\n",
+    "### Declarations\n",
+    "Here is how you create variables in C++:\n",
+    "\n",
+    "```c++\n",
+    "auto x = 1;  // create an integer variable\n",
+    "auto y = 1.0; // create a double variable\n",
+    "auto z = 2U; // create an unsigned integer variable\n",
+    "```\n",
+    "\n",
+    "A variable stores a value. If you have a value you want to store, assign it to a name of your choosing with the `auto` keyword before it. \n",
+    "\n",
+    "Instead of the `=` sign above, we could braces `{` and `}` to set th initial values.\n",
+    "\n",
+    "```c++\n",
+    "auto x{1};  // create an integer variable\n",
+    "auto y{1.0}; // create a double variable\n",
+    "auto z{2U}; // create an unsigned integer variable\n",
+    "```\n",
+    "\n",
+    "Another alternative syntax for declarations is as follows. In these declarations, we explicitly tell the type of the values we want:\n",
+    "\n",
+    "```c++\n",
+    "int x = 1;\n",
+    "double y = 1.0;\n",
+    "unsigned int z = 1U;\n",
+    "```\n",
+    "\n",
+    "or using braces:\n",
+    "\n",
+    "```c++\n",
+    "int x{1};\n",
+    "double y{1.0};\n",
+    "unsigned int z{1U};\n",
+    "```\n",
+    "\n",
+    "When using braces with explicit type specification above, the compiler can apply some additional checks. For instance, in `int x{1}`, we have told the \n",
+    "compiler that we are trying to create an integer. If we then try to initialize it with `1.4`, it will report it as an error. `int x = 1.4`, on the other hand,\n",
+    "will be accepted silently, converting the `1.4` in to the specified type, `int`. We will have a variable of `int` type with a value `1`. If we wrote `int i{1.4}`,\n",
+    "it is not a very sane thing to do. There are some possibilities:\n",
+    "\n",
+    "    - we wanted to write double, but wrote int by mistake\n",
+    "    - we wanted to write 14 but typed an extra dot at the wrong place\n",
+    "    - other equally weird scenarios, none of them is \"exactly what we want\"\n",
+    "    \n",
+    "It is useful if the compiler gives us an error in such situations. The brace `{`, `}` syntax for initialisation is therefore somewhat more restrictive, and\n",
+    "should be preferred. It also allows us to set variables to their default initial values:\n",
+    "```c++\n",
+    "unsigned long counter{};\n",
+    "```\n",
+    "In the above, we create an unsigned long integer type with its default initial value, $0$. Since we are telling the type directly, this can work, whereas `auto counter{}` would be meaningless, as `auto` infers the type from the initialiser expression. When using explicit typenames to declare a variable, we can completely skip the initial value, e.g., `double x;`. `x` is then created uninitialised. There are special cases where even such an expression will lead to `x` being nicely zero initialised, but it is much better to always initialise with a literal value or with the default value explicitly. It is not recommended to leave the initializer out for built in types. For user defined types, C++ offers so much control that the creater of that user defined type gets to decide whether `UserdefinedType X` should create `X` uninitialised, zero initialised or initialised to any other sensible value."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Using variables in expresions\n",
+    "\n",
+    "If you write an expression using variable names, when evaluating (finding the value of) that expression, the variable names are substituted by their values. \n",
+    "\n",
+    "Let's also note here that the symbol `=` in C++ means \"assign\". `X = Y` means take the value of the entity on the right and put it in the object with the name `X`. We are not asking whether `X` is equal to `Y`. For that comparison, like in many other languages, C++ uses `==`. If `X` is an integer, `5 == X` is always a valid expression, which is either true or false, but `5 = X` is syntactically meaningless, because you can not give a new value to $5$."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Quiz: What does `X = X + 1` mean ?\n",
+    "\n",
+    "\n",
+    "    A. X cancels out on both sides and we have 0 equals 1\n",
+    "    B. Whatever value X had before, increase it by 1"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**Aside:** Historically, the choice of `=` for assignment (so that we have to type `==` when we want to check if two values are equal) goes back to a time before keyboard inputs and the Fortran language. It is a small shift to get used to, and no other token proposed for this very important operation, `:=`, `->`, `<-` etc. consist of a single character. In a typical C++ program, you will need assignment far more often than equality comparison, so that most programmers support this notation."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Static typing\n",
+    "\n",
+    "C++ is a \"statically typed\" language. Every time you bring a variable to existence to store something for a while, the compiler must be given a \"type\" for the values to be stored in it.  In C++, the type is associated with a variable at the point it enters the code, through the \"declaration\". Throughout the life of that variable, it has the same type. It is not possible for a variable to change from being a string to being an integer. This point is important to understand for people who have programmed in python and are learning C++. The following is perfectly acceptable in python:\n",
+    "\n",
+    "```python\n",
+    "# Python code to make a contrast\n",
+    "v = \"1\" + \"2\" + \"3\"\n",
+    "print(v)\n",
+    "v = int(v)\n",
+    "```\n",
+    "If you run the above in a Jupyter notebook with a python3 kernel, you can verify the type of the variable `v` after each statement, using `type(v)` after each statement. You will see that `v` becomes an `int` after the last line above, whereas it starts out being a `str`. Such a thing will never be allowed in C++. The type of an entity is set when you declare it. It can not be changed by assignment. Allowing that would make reasoning about properties of a variable extremely hard: the type of a variable in one given line of code might end up depending on the code path taken to reach a particular line. To emphasize it further, consider this:\n",
+    "\n",
+    "```python\n",
+    "# Python code to make a contrast\n",
+    "v = \"1\" + \"2\" + \"3\"\n",
+    "for i in range(10):\n",
+    "    print(v)\n",
+    "    if len(v) > 7:\n",
+    "        v = int(v)\n",
+    "    v = v + v\n",
+    "\n",
+    "```\n",
+    "\n",
+    "How the variable `v` is changed in the line `v = v + v` depends on the type of `v`. If it is a string, \"123\", it will become \"123123\", by concatenation. If is an integer, 123, it will become 246. We have to consider the immediate history of the variable to know what will actually happen in the line `v = v + v`. Statically typed languages avoid this entire category of problems by making types of variables constants. In any C++ code, a variable which starts out as an object of type T will end its life as an object of type T.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Quiz: Does the variable declaration with `auto` affect the fact that C++ has compile time fixed types?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The answer is no. Because in every version of the variable declaration with `auto` you saw above, the compiler can infer and set a unique type for the object you create. The `auto` keyword just spares the human programmer from typing everything by hand, but `double X{1.5};` and `auto X{1.5};` are completely equivalent."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Type promotion in expressions\n",
+    "\n",
+    "The usual `+`, `-`, `*` and `/` operators can be used with the integral and floating point number types. For integral types, `/` is the integer division and `%` is the remainder operator. If the operands to the arithmetic operation have the same type, i.e., `int + int`, the result also has the same type. If the operands have different types, the smaller *type* is promoted to the larger *type*, so that the result ends up having the larger type (see below). Floating point types are to be considered \"larger\" for this purpose."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "auto m = 99;\n",
+    "auto y{23}, z{44};\n",
+    "auto x = y * z + m; // y * z + m is an int, like y, z and m. Therefore, x is an int\n",
+    "auto low = 10;\n",
+    "auto high = 13;\n",
+    "auto lq = high / low; // lq is of type int, and a value 1\n",
+    "auto lr = high % low; // lr is of type int and value 3\n",
+    "auto BIGVAL = 5000'000'000UL; // unsigned long\n",
+    "auto fq = 13.0 / low; // fq is type double and value 1.3\n",
+    "float f = 1.2; \n",
+    "auto v = f * BIGVAL; // v is a float\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "low & high"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The above result is because `low` is 1010 in binary, and `high` is 1101, and `low & high` is **bitwise and** operation on the two integers. Similarly there is *bitwise or* `|`, *bitwise exclusive or* `^` and *bitwise not* `~`.\n",
+    "\n",
+    "**Exercise:** Use the showbits() function from earlier to print out the bits of `low`, `high` and `low & high`, to understand what the bitwise `&` operator did. Do the same for the other bitwise operators."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "There are also logical operators working on boolean values *true* and *false*, `&&`, `||`, `^^` and `!`. For variables which are not of type `bool`,  when they are used with these logical operations, they are converted to a true/false value. Typically, values were all bits are zero are interpreted as false, and every other value is regarded as true. Guess the output of the following cell before executing it!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// This is valid code, although the cling interpreter seems to have problems with it.\n",
+    "low && high"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Logical operators in C++ can be written alternatively as `and`, `or` etc. For example, `a && b` could be written as `a and b`, `a or b` can be written as `a or b`, for greater readability. Full table for alternative tokens can be found [here](https://en.cppreference.com/w/cpp/language/operator_alternative)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "low and high"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Fused assignment and arithmetic/bitwise operators\n",
+    "\n",
+    "It is possible to shorten `a = a + b` to `a += b`, `a = a - b` to `a -= b` and so on for all arithmetic operators. The same can be done for bitwise operators, i.e., `a = a & b` can be written as `a &= b` and so on. By contrast, there is no fused assignment for logical `&&`, `||` operators. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "low &= high ; \n",
+    "low"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "As we have discussed before, `==` serves as the comparison for equality in C++. The expression `a == b` is either true or false, depending on the values of `a` and `b`. The expression `a = b` is quite different: this means \"store the value of b in a \\[converting the value to the type of a if necessary\\]\". Other comparison operators are `!=` for \"not equal to\", and `<`, `>`, `<=`, `>=`, for \"less than\", \"greater than\", \"less than or equal to\" and \"greater than or equal to\" respectively. "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Increment and decrement operators\n",
+    "\n",
+    "Like C, the operators `++` and `--` are used to indicate increment and decrement of a given variable, respectively. Both operators can be placed before or after the variable name for built in numeric types, `int`, `long`, `short`, `char` (and unsigned counterparts), `double`, `float` and `long double`. For user defined types, the meaning of the operator is decided by the implementor of that type. In all cases, there is a slight difference in the meaning between the prefix (e.g., `++i`) and postfix (e.g., `i++`) forms. To understand that, we have to start recognising \"value of an expression\" and \"side effects of an expression\". \n",
+    "\n",
+    "`2 * x` is an expression involving the variable `x`. If `x` is currently `1`, `2 * x` has a *value* of `2`. When we evaluate the expression `2 * x` there are no side effects on `x`. After we have evaluated `2 * x`, `x` is still `1`. But, `x = 4` is also an expression. Its value is the value of `x` after the assignment, i.e., `4`. But it also has a side effect. Whatever `x` was before, it has now changed to a value of `4`. Prefix and postfix `++` (or `--`) operators have the same side effect. They both increase a variable by 1. But they have different values. The value of a prefix `++` operator is the already incremented value, whereas the value of the postfix operator is the old value. With examples:\n",
+    "\n",
+    "```c++\n",
+    "auto i{0};\n",
+    "auto k = ++i; // i is now 1, but so is k\n",
+    "cout << i << \"\\t\" << k << \"\\n\";\n",
+    "auto l = i++; // i is now 2, but l is 1\n",
+    "cout << i << \"\\t\" << l << \"\\n\";\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    auto i{0};\n",
+    "    auto k = ++i; // i is now 1, but so is k\n",
+    "    cout << i << \"\\t\" << k << \"\\n\";\n",
+    "    auto l = i++; // i is now 2, but l is 1\n",
+    "    cout << i << \"\\t\" << l << \"\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "- Pre-in(de)crement : In(de)crease and use the new value\n",
+    "- Post-in(de)crement : In(de)crease, but use the old value\n",
+    "\n",
+    "Typically, the implementation of the post-increment or post-decrement operators involves more steps (e.g., make a backup, change, return the backup value) than the prefix versions (change, return the changed value). It is therefore a good habbit to cultivate to always write `++i` by default, and only do `i++` when you have a compelling reason to do so.\n",
+    "\n",
+    "**Aside:** The name \"C++\", for our language, is therefore not the best choice! It means, in its own syntax, \"increment C, and then use the old C\"! It should have been \"++C\"!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "C++17",
+   "language": "C++",
+   "name": "cling-cpp17"
+  },
+  "language_info": {
+   "codemirror_mode": "c++",
+   "file_extension": ".c++",
+   "mimetype": "text/x-c++src",
+   "name": "c++"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/notebooks/Fundamentals_2.ipynb b/notebooks/Fundamentals_2.ipynb
new file mode 100644
index 0000000..d6342db
--- /dev/null
+++ b/notebooks/Fundamentals_2.ipynb
@@ -0,0 +1,1048 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Getting started with C++ using Jupyter notebook: Part 2\n",
+    "\n",
+    "This notebook assumes that you did the Fundamentals_1 notebook earlier.\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#pragma cling add_include_path(\"/p/project/training2213/local/include\")\n",
+    "// Hopefully, you have read the introductory chapters in the course book and understand\n",
+    "// the purpose of the include statements. The specific include files we are using here\n",
+    "// will be explained later.\n",
+    "\n",
+    "// The contents of this cell are to set up this notebook. You don't need to understand\n",
+    "// how this works right now. Run this and move on!\n",
+    "#include <iostream>\n",
+    "#include <type_traits>\n",
+    "#include <string>\n",
+    "#include <vector>\n",
+    "#include <map>\n",
+    "#include <cmath>\n",
+    "#include <algorithm>\n",
+    "#include <typeinfo>\n",
+    "using namespace std;\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**Run only one of the following cells. If the first one works, leave the second one alone. If not, uncomment the code in the second cell and it.** "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <boost/type_index.hpp>\n",
+    "template <class T>\n",
+    "void typeof(T&& t) {\n",
+    "    std::cout << \"Type name: \" << boost::typeindex::type_id_with_cvr<T>().pretty_name() << \"\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// template <class T>\n",
+    "// void typeof(T&& t) {\n",
+    "//    std::cout << \"Type name: \" << typeid(t).name() << \"\\n\";\n",
+    "//}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <binform17.hh>\n",
+    "using namespace cxx2022;\n",
+    "// The header declares functions in the namespace 2022."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Creating duplicates\n",
+    "\n",
+    "To create a duplicate of an existing variable `x`, we can do any of the following:\n",
+    "```c++\n",
+    "auto y1 = x;\n",
+    "auto y2{x};\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Duplicate name stickers and creating aliases\n",
+    "When you declare variable as described earlier, you do two things: \n",
+    "\n",
+    "    - create an object storing the value you gave it. \n",
+    "    - create a \"name\" which you stick to that object. \n",
+    "\n",
+    "The name is a \"reference\" to the newly created object. It is possible to attach another name sticker to the same object:\n",
+    "\n",
+    "```\n",
+    "auto& x2 = x;\n",
+    "```\n",
+    "\n",
+    "Here, we are saying that we only want to give another name tag to the object with the name tag `x`. We do not want to create a new entity. Below, `x` and `x2` are aliases, since `x2` is created as a reference. `y` and `y2` are not aliases. `y2` is created as a duplicate object. Observe what happens when we change and print their values..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    auto x = 0;\n",
+    "    auto& x2 = x;\n",
+    "    auto y = 10;\n",
+    "    auto y2 = y;\n",
+    "    cout << \"x = \" << x << \"\\tx2 = \" << x2 << \"\\ty = \" << y << \"\\ty2 = \" << y2 << \"\\n\";\n",
+    "    x = x + 1;\n",
+    "    y = y + 1;\n",
+    "    cout << \"x = \" << x << \"\\tx2 = \" << x2 << \"\\ty = \" << y << \"\\ty2 = \" << y2 << \"\\n\";\n",
+    "    x2 = x2 + 1;\n",
+    "    y2 = y2 + 1;\n",
+    "    cout << \"x = \" << x << \"\\tx2 = \" << x2 << \"\\ty = \" << y << \"\\ty2 = \" << y2 << \"\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "If you write an expression using variable names, when evaluating (finding the value of) that expression, the variable names are substituted by their values. \n",
+    "\n",
+    "Let's also note here that the symbol `=` in C++ means \"assign\". `X = Y` means take the value of the entity on the right and put it in the object with the name `X`. We are not asking whether `X` is equal to `Y`. For that comparison, like in many other languages, C++ uses `==`. If `X` is an integer, `5 == X` is always a valid expression, which is either true or false, but `5 = X` is syntactically meaningless, because you can not give a new value to $5$."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Quiz: What does `X = X + 1` mean ?\n",
+    "\n",
+    "\n",
+    "    A. X cancels out on both sides and we have 0 equals 1\n",
+    "    B. Whatever value X had before, increase it by 1"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**Aside:** Historically, the choice of `=` for assignment (so that we have to type `==` when we want to check if two values are equal) goes back to a time before keyboard inputs and the Fortran language. It is a small shift to get used to, and no other token proposed for this very important operation, `:=`, `->`, `<-` etc. consist of a single character. In a typical C++ program, you will need assignment far more often than equality comparison, so that most programmers support this notation."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Strings\n",
+    "\n",
+    "std::string is a type to represent character strings. It is a class provided by the C++ standard library, not a built in type in the language, but since it is a rather fundamental type we often need, e.g., names of people, places, chemicals, filenames ..., it is useful to know how to use it. To have access to standard library strings, we need to include the string header, i.e., put `#include <string>` somewhere at the beginning of a C++ program. We did that in the first \"you will understand later\" cell at the top of this notebook. Once we have included `<string>`, (and placed `using namespace std;` somewhere above,) we can declare and use strings as follows..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    string fullname; // Without an explicit initialiser, strings are created empty\n",
+    "    string name{\"Albert\"};\n",
+    "    string surname{\"Einstein\"};\n",
+    "    //Concatenation and assignment\n",
+    "    fullname = name + \" \" + surname;\n",
+    "    // Comparison\n",
+    "    if (name == surname)\n",
+    "       cout << \"You have the same first and last name! That's interesting!\\n\";\n",
+    "    else\n",
+    "       cout << \"Hello, \" << fullname << \"\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    // Converting back and forth between strings and numbers\n",
+    "    string numstr1{\"3.1415926\"}, numstr2{\"53589793\"};\n",
+    "    auto totstr = numstr1 + numstr2;\n",
+    "    cout << \"Combined string is \" << totstr << \"\\n\";\n",
+    "    cout << \"Sin(\" << totstr << \") = \" << sin(stod(totstr)) << \"\\n\";\n",
+    "    // stod means string to double. Similarly stoi means string to integer.\n",
+    "    // we can convert numstr2 above into an integer ...\n",
+    "    cout << \"Second part, divided by 155 leaves a remainder \" << stoi(numstr2) % 155 << \"\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// You can only convert string to numbers if those strings are in fact numbers. \n",
+    "// Otherwise you get an \"exception\"...\n",
+    "try {\n",
+    "    cout << stoi(\"Hello\") << \"\\n\";\n",
+    "} catch (std::exception& err) {\n",
+    "    std::cout << \"Caught exception \" << err.what() << \"\\n\";\n",
+    "}\n",
+    "// We will learn about error handling with exceptions later"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Constants\n",
+    "\n",
+    "Variables, as you have seen above, can change the value they store. A lot of programming becomes easier when you have access to such entities. Sometimes, we want variables (objects with names) to hold on to a specific value, and never change. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    auto G = 6.674e-11;\n",
+    "    auto m1 = 1.0e10, m2 = 1.0e4;\n",
+    "    auto r = 10;\n",
+    "    std::cout << \"Force = \" << -G * m1 * m2 / (r * r) << \"\\n\"; // great!\n",
+    "    G = G + 1;\n",
+    "    std::cout << \"Force = \" << -G * m1 * m2 / (r * r) << \"\\n\"; // wrong!\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The above mistake was deliberately put in an easily detectable spot, to make a point. Some things should not be allowed to change. We can not simply rely on the politeness and infalibility of others to ensure that vital constants do not change in our program. In this day and age, our lives may depend on it. In C++, we can attach a `const` qualifier to the type to make a variable into a constant. When we create a `const` object, it can be initialised to any value at the point of its creation, but once created, it holds on to that same value, disallowing any further changes. Compiler will simply not accept code where we try to change a `const` qualified object."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    const auto G = 6.674e-11;\n",
+    "    const auto m1 = 1.0e10, m2 = 1.0e4;\n",
+    "    auto r = 10;\n",
+    "    auto force = -G * m1 * m2 / (r * r); // great!\n",
+    "    G = G + 1; // Will never compile\n",
+    "    auto force2 = -G * m1 * m2 / (r * r); // Would have been a wrong answer, but will never happen, \n",
+    "                                     // because the compiler will not allow the reason for the \n",
+    "                                     // incorrect answer (G = G + 1) to ever happen.\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Since it is possible to create multiple accessors or references to the same object, can we create an alias for `G` and change it sneakily ? "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "const auto G = 6.674e-11;\n",
+    "auto& G2 = G;\n",
+    "G2 = G2 + 1; // Nope!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "As you can see, the second reference we created had no more \"privilege\" than the first reference `G`. It became a reference to a `const double` so that the object accessed through it remained immutable. It is however possible to create aliases with reduced privileges: \n",
+    "\n",
+    "We have a normal mutable variable. We want to create and use an alias for some calculations, but we don't want to accidentally change the variable during those calculations. We can do this:\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    auto R = 0.7;\n",
+    "    const auto& r = R;\n",
+    "    // calculate using the value stored in R, but using a \"read only accessor\" \n",
+    "    cout << \"Area = \" << 3.1415927 * r * r << \"\\n\"; // This is ok. We are not changing r.\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// If we, by mistake, write this ...\n",
+    "{\n",
+    "    auto R = 0.7;\n",
+    "    const auto& r = R;\n",
+    "    // calculate using the value stored in R, but using a \"read only accessor\" \n",
+    "    cout << \"Area = \" << 3.1415927 * r * r << \"\\n\"; // This is ok. We are not changing r.\n",
+    "    r = r * r; // it won't compile\n",
+    "}\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "It is therefore possible and useful to create `const` references to normal mutable variables. Because the constant reference is an accessor of reduced previlige. Being more restricted, it can not break any guarantees we previously had. We can not create non-constant references out of constant ones, because you would be allowed to change the object through the non-constant reference. You can also not attach a non-constant reference to a pure (R-)value:\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    auto& x = 6;\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Restrictions such as the ones for `const` qualified objects ensure that certain kinds of errors can not happen in our programs. If we violate the constantness guarantees, the program fails to compile. If it compiles and runs, we can be sure that none of the 5000 libraries we are using is changing the value of the universal gravitational constant or the speed of light. \n",
+    "\n",
+    "It is normally good practice to create variables `const` by default, unless it really needs mutability to do what it is supposed to do."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**Note:** The C++ programmers community is nearly split equally between people who like writing `const` before the typename (including me, but only out of habbit) and those who prefer to always write it after the type, e.g., `double const G{6.674e-11};`. This \"east-const\" style is a bit more consistent across all uses of `const` in C++, because `const` actually applies to what's on its left. Only when there is nothing there does it bind to the typename on the right. If this is the first time you are learning to use `const`, perhaps you should put it on the right, like one puts adjectives after the noun in romance languages. No matter how you choose to write it, you should be aware that the other style exists, so that reading code with `const` in the other order does not confuse you. `int const` and `const int` are the same thing."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "For the next exercise, let's start with a few variable declarations."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    int x;\n",
+    "    int y = 2;\n",
+    "    int z{y};\n",
+    "    double w{4.};\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Exercise\n",
+    "In this notebook, you can always find out the type of any expression by using the `typeof` function. For instance, `typeof(5)` will tell you that 5 is an `int`. Use the cell below to find out the types of the various symbols in the declarations above. *Note that unless the cell with typeof() function based on boost type_index worked at the beginning of this notebook, our type finding function does not keep information about references!*"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    int x;\n",
+    "    int y = 2;\n",
+    "    int z{y};\n",
+    "    int& yr{y};\n",
+    "    double w{4.};\n",
+    "    typeof(w);\n",
+    "    typeof(4.0);\n",
+    "    typeof(z + y);\n",
+    "    typeof(yr);\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    std::string fullname{\"Longish Name\"};\n",
+    "    typeof(fullname);\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Type of a string is shown as a longish name, which is the true internal name of the string type in use since C++11. "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## L-values, R-values, references\n",
+    "\n",
+    "You might have noticed that 4.0 has a type `double`, but `w` is of the type `double&`. Recall that when you declare a variable, you do two things: make an object of the given type and give it a name or \"reference\". The name of a variable is a so called L-value reference to the object we create. L-value references are written with an ampersand `&` on the right in C++. That's why we see these `&` in the types of all named variables here, whereas strict values, like 2, 4.0 etc, which do not have any variable name, show as plain `int`, `double` etc. \n",
+    "\n",
+    "In C++, we distinguish between things which can or can not stand on the left hand side of an assignment operator.\n",
+    "\n",
+    "`x = 5;` makes sense: we store 5 in `x`. \n",
+    "\n",
+    "`6 = 5` makes no sense. 6 is not something whose value can be changed. \n",
+    "\n",
+    "Similarly `(x + y) = 5` does not make any sense. We want to store 5 somewhere, but where ? \n",
+    "\n",
+    "Things like 5, `x + y`, which can not be on the left hand side of an assignment expression are called R-values (they can only be on the Right side of the `=` symbol). Things like variable names which can also meaningfully appear on the left side in an assignment expression are called L-values. Our variable names are a type of entities in C++ known as L-value references.\n",
+    "\n",
+    "Whenever you use a reference in an expression, like `x + y * z`, the references like `x` are replaced by the values they store. So, you could almost always get by pretending that `x` is a `double`. Only when you explicitly try to find out the type of a named variable will you see that it is in fact a little different from the type it stores!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Let's try to create a few references from some variables to understand an aspect of C++, which will be very important during our discussion of classes."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// A few variables to set the stage for this experiment\n",
+    "auto v1{17}, v2{23}; // v1 and v2 are integers with values 17 and 23"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "auto& v1r{v1}; // No problem. v1r is now another name for the object v1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "auto& v2r{v2}; // No problem, obviously!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "auto& v1pv2lvr{v1 + v2}; // Problems."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The syntactic meaning of what we were trying to do above is, \"make a new entity called v1pv2lvr, which is an alias of the object called `v1+v2`\". The reason the above fails is that `v1+v2` is a temporary result of a calculation, not a named variable. It is not an L-value reference. We therefore can not create an L-value reference `v1pv2lvr` out of it. When we explicitly create an L-value reference (by declaring it as `auto& something` or `SomeType& something`) the initializer expression must be an L-value reference (named variables, array elements ...), i.e., an entity which would make sense on the left side of an assignment symbol.\n",
+    "\n",
+    "So, you can not make L-value references to things like `5`, `3 * v1 + v2` etc. Because they are not L-values but R-values. \"Could I make an R-value reference instead ?\", I hear you ask. The answer, my good padawan, is yes. R-value references are written as `SomeType&&`, i.e., as a typename followed by two ampersands. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "int&& v1pv2rvr{v1 + v2}; // Allowed"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The syntactic meaning of the above is \"make a new entity called v1pv2rvr, which should be the new name of a hitherto nameless result of the initializer expression\". If the initializer expression is an R-value, you can create an R-value reference to that as above. But once you have given a name to that nameless entity, you can use that as a normal L-value reference, i.e., you can use `v1pv2rvr` on the left side of an assignment symbol. `v1pv2rvr` is a name, and hence an L-value reference. It was created out of a nameless entity, which was an R-value. Therefore the different declaration."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "typeof(v1pv2rvr);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// But this does not work!\n",
+    "int&& v1rvr{v1};"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You may have noticed that we did not use `auto&&` above to create `v1pv2rvr`. This is because `auto&&` is a bit more general: it means \n",
+    "\n",
+    "    -L-value reference if the initializer is an L-value reference,\n",
+    "    -R-value reference if the initializer is an R-value\n",
+    "\n",
+    "Irrespective of what the initializer is, we end up with something we can use like an L-value reference."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "auto&& v1rvr{v1}; // OK"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "auto&& v1pv2r{ v1 + v2 }; // OK"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "typeof(v1rvr);\n",
+    "typeof(v1pv2r);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    " `auto&` and `auto&&` both also copy the constness of the initializer."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "const int v3{34};\n",
+    "auto&& v3r{v3};\n",
+    "typeof(v3r);\n",
+    "auto& v3r2{v3r};\n",
+    "typeof(v3r2);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Assignment expressions"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The left hand side of an assignment operator must be an L-value reference. For the assignment operator, this reference is not substituted by its value, as that would be pointless. If `X`, the integer, is currently holding `1`, and we write `X = 0` we are not saying that change the value of `1` to `0`. We are saying `X` should now hold `0`. \n",
+    "\n",
+    "It is possible to assign different **values** to variables after they have been declared. That process is called assignment. Assignment **may change the value, but can not change the type** of the left hand side of the assignment symbol:\n",
+    "```c++\n",
+    "X = 4; // X is still an integer. But now it contains a value 4.\n",
+    "```\n",
+    "If the right hand side (RHS) of the assignment operator `=` has a different type than the left hand side(LHS), the assignment can only succeed if that value can be converted to the type of the LHS.\n",
+    "```c++\n",
+    "double w{77.9};\n",
+    "w = 1; // w is still a double. It now holds the value 1.0. \n",
+    "       // The integer 1 on the right hand side is converted to a double precision value 1.0\n",
+    "```\n",
+    "The bit representation of integer 1 is \"0000 .... 0001\", where as that of double precision 1 is \"0011111111110000000....00000000\". As far as the computer is concerned, `w = 1` and `w = 1.0` above are quite different things. But, since `w` is of the type `double`, and that can not change, the incoming value is converted to the appropriate type, and then assigned.\n",
+    "\n",
+    "The point being made here is not that it takes extra time for these assignments. It does not need extra time in this case, because `1` is a constant known at compile time, and hence the conversion can happen during compilation. We are just drawing attention to what happens during assignment, and yes, if the type conversion can not happen at compile time (RHS is another variable whose value is not known before the program runs), the type conversion has an (often small but non-zero) overhead."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### References: summary for the impatient:\n",
+    "\n",
+    "- Create a new duplicate variable from existing variable : \n",
+    "    + TYPENAME newvar{oldvar};\n",
+    "    + auto newvar{oldvar};\n",
+    "- Create an alias (reference) to an existing variable :\n",
+    "    + TYPENAME& newvar{oldvar};\n",
+    "    + auto& newvar{oldvar};\n",
+    "    + auto&& newvar{oldvar};\n",
+    "- Create a reference to an existing variable with no write access:\n",
+    "    + const TYPENAME& newvar{oldvar};\n",
+    "    + const auto& newvar{oldvar};\n",
+    "- Create a reference to a temporary nameless object:\n",
+    "    + TYPENAME&& newvar{init_expr};\n",
+    "    + auto&& newvar{init_expr};"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Addresses and pointers\n",
+    "\n",
+    "Every object which is allowed to be on the left side of an assignment operation has a particular location in memory storing its state. The bytes in that memory location, when interpreted by the rules of the type, yield the stored value. For a mental model, just imagine that the computer memory is a very long street in which each byte has a numbered address. The address of the first byte storing the state of an object is regarded as the address of that object. Address of an object identified by the name `X` can be obtained by `std::addressof(X)` or by `&X`. The number of bytes used to store the state of an object on the stack can be queried using the `sizeof` operator.\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    #include <iostream>\n",
+    "    double X{2.0};\n",
+    "    int i{2021};\n",
+    "    std::cout << \"Variable X, value = \" << X\n",
+    "          << \", size in bytes = \" << sizeof(decltype(X)) \n",
+    "          << \", location in memory = \" << (size_t) std::addressof(X) << \"\\n\";\n",
+    "    std::cout << \"Variable i, value = \" << i\n",
+    "          << \", size in bytes = \" << sizeof(decltype(i)) \n",
+    "          << \", location in memory = \" << (size_t) std::addressof(i) << \"\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "There is a built-in type in C++ to store addresses of objects. They are called pointers. For every type `T`, there is an associated pointer type `T*`. Objects of type `T*` can store addresses belonging to objects of type `T`. Although addresses are just byte locations in memory, it is useful to distinguish between pointers to different types.\n",
+    "\n",
+    "Pointers are described in detail in the companion book, chapter 2. We will not discuss it any further in this notebook, but will return to the topic as and when required. For now, it suffices to know that they store addresses of variables, and those addresses can be obtained as shown above.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Conditionals\n",
+    "\n",
+    "### if ... else if ... else\n",
+    "```c++\n",
+    "if (condition) do_something;\n",
+    "if (condition) {\n",
+    "    one_thing;\n",
+    "    another_thing;\n",
+    "    many_things;\n",
+    "}\n",
+    "if (condition) do_something;\n",
+    "else do_something_else;\n",
+    "if (one_or_more_declarations; condition) ...\n",
+    "```\n",
+    "The primary conditional branch statement in C++ is the `if ... else ...` statement, and a few different ways to write them are schematically shown above. The obvious interpretation is the correct one. The conditional statement can contain one or more variable declarations before the boolean expression in the parentheses enclosing the \"condition\" part. Variables declared there can be used in the `if` as well as the `else` part of the conditional block (more about variable lifetime soon!). Examples:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    auto high{55};\n",
+    "    if (high % 3 == 0) cout << high << \" is divisible by 3\\n\";\n",
+    "    else cout << high << \" is not divisible by 3\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "It is possible to chain as many `if` statements as required if different actions need to be taken based on many different conditions. For instance,\n",
+    "```c++\n",
+    "if (value < 10.) do_A;\n",
+    "else if (value < 20.) do_B;\n",
+    "else if (value < 30.) do_C;\n",
+    "else if (whatever) do_X;\n",
+    "...\n",
+    "else do_Z;\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### switch\n",
+    "\n",
+    "The `if` statement allows us to branch in to two alternative actions based on a condition. The `switch` block allows us to branch into an arbitrarily many alternative actions based on the value of an integral type.\n",
+    "\n",
+    "```c++\n",
+    "switch (high - low) {\n",
+    "    case 0 : cout << \"high and low can not have the same value\\n\"; break;\n",
+    "    case 1 : \n",
+    "    case 2 : cout << \"a difference of 1 or 2 between the limits is still too low\\n\"; break;\n",
+    "    default : cout << \"The limits are acceptable\\n\";\n",
+    "};\n",
+    "```\n",
+    "If the value passed to the switch statement matches any of the \"cases\" inside the switch block, the program jumps to the label for that particular case **and continues executing until the end or until it sees a `break` statement**."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "switch (high - low) {\n",
+    "    case 0 : cout << \"high and low can not have the same value\\n\"; break;\n",
+    "    case 1 :\n",
+    "    case 2 : cout << \"a difference of 1 or 2 between the limits is still too low\\n\"; break;\n",
+    "    default : cout << \"The limits are acceptable\\n\";\n",
+    "};"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Ternary expression `? :`\n",
+    "\n",
+    "The ternary expression has the form, `condition ? value_if_true : value_if_false`. It is often used to express that we want to assign one of two values, depending on some logical condition.\n",
+    "```c++\n",
+    "res = (r < cost) ? calc : 0. ;\n",
+    "```\n",
+    "In the above, `r` and `cost` are presumably some  variables, and the value assigned to `res` is `calc` if `r` is less than `cost`, and `0.` otherwise. In other words, we could write the above as,\n",
+    "```c++\n",
+    "if (r<cost) res = calc;\n",
+    "else res = 0.;\n",
+    "```\n",
+    "The ternary alternative might be more compact / expressive in some cases."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Iterations\n",
+    "\n",
+    "Loop constructs allow us to repeat an action consisting of one or more statements as many times as we need."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `while` loops"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    auto curr{0}, lim{10};\n",
+    "    while (curr < lim) {\n",
+    "        cout << \"Value = \" << curr << \"\\n\";\n",
+    "        ++curr;\n",
+    "    }\n",
+    "}\n",
+    "// Run this cell as it is. Then re-run after changing the limit to 0. How many times is the loop body executed ?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`while` loops have the basic syntax:\n",
+    "```c++\n",
+    "while (condition) { body }\n",
+    "```\n",
+    "They execute a statement or a brace enclosed series of statements repeatedly while a certain condition remains true. Conceptually,\n",
+    "\n",
+    "1. Evaluate condition\n",
+    "2. If false, jump to 5\n",
+    "4. Loop body\n",
+    "5. Back to 1.\n",
+    "6. End of loop"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `do ... while` loops"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    int curr{0}, lim{10};\n",
+    "    do {\n",
+    "        cout << \"value = \" << curr << \"\\n\";\n",
+    "        ++curr;\n",
+    "    } while (curr < lim);\n",
+    "}\n",
+    "// Run this cell as it is. Then re-run after changing the limit to 0. \n",
+    "// How many times is the loop body executed ?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Web based environments like Jupyterlab and online C++ compilers such as coliru and wandbox do not currently handle\n",
+    "standard input well. We therefore do not get any opportunity to enter a value, whereas the above code in a real\n",
+    "program would stop for user input."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The syntax of the `do ... while` loop can be schematically written as:\n",
+    "```c++\n",
+    "do { body } while (condition);\n",
+    "```\n",
+    "Conceptually, it is:\n",
+    "\n",
+    "1. Execute body\n",
+    "2. Evaluate condition\n",
+    "2. if conditino is true, back to 1\n",
+    "2. End of loop"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The body of the `do ... while` loop is executed at least once, where as the body of the `while` loop is executed zero or more times depending on the loop condition at the point of entry."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Range based for loops (\"for each\" loops)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    std::string s{\"Sunday\"};\n",
+    "    for (auto day : {\"Monday\", \"Tuesday\", \"Wednessday\", \"Thursday\", \"Friday\", \"Saturday\", \"Sunday\"}) {\n",
+    "        cout << day << \" comes after \" << s << \"\\n\";\n",
+    "        s = day;\n",
+    "    }\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Range based for loops work on each element in a sequence. Typically, these sequences are standard library containers, and more examples will be given once the containers are introduced."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `for` loops"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "for (int i = 0; i < 10; ++i) cout << \"counter = \" << i << \"\\n\"; // ++i means increase i by 1. "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`for` loops have the basic syntax:\n",
+    "```c++\n",
+    "for (init ; continuation_condtion ; increment) { body }\n",
+    "```\n",
+    "As usual, if the body to be repeated is a single statement, we can omit the braces `{` and `}` around it. The loop is executed as long as the condition is true. Conceptually, this is how it works:\n",
+    "\n",
+    "1. The initialisation is executed. \n",
+    "1. The condition is evaluated\n",
+    "1. If the condition evaluates to false, jump to 7\n",
+    "1. Loop body\n",
+    "1. The increment part is evaluated\n",
+    "1. Back to 2\n",
+    "1. End of loop\n",
+    "\n",
+    "The parenthesis in the loop head must have the two `;` separating the initialisation, condition and the increment. But we can leave out any of these. For instance, the following will repeat the loop body indefinitely:\n",
+    "```c++\n",
+    "for (;;) { body }\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Error handling with exceptions\n",
+    "\n",
+    "In C++, there are many different ways of handling errors happening at program execution time. The exceptions are one of the oldest. The idea is that when an error occurs, we write code to \"throw an exception\". Program execution then does not continue to the next line, but directly to a point where the exception is \"caught\" and handled.\n",
+    "\n",
+    "In order to watch for possible exceptions coming out of a region of code, we have to wrap it in a `try ... catch` set up.\n",
+    "\n",
+    "```c++\n",
+    "std::string inp{\"3.14159\"};\n",
+    "try {\n",
+    "    auto num = std::stod(inp);\n",
+    "    std::cout << \"Square root of \" << num << \" is \" << std::sqrt(num) << \"\\n\";\n",
+    "} catch (std::exception& error) {\n",
+    "    std::cout << \"Error : \" << error.what() << \"\\n\";\n",
+    "}\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    std::string inp{\"3.14159\"};\n",
+    "    try {\n",
+    "        auto num = std::stod(inp);\n",
+    "        std::cout << \"Cube root of \" << num << \" is \" << std::cbrt(num) << \"\\n\";\n",
+    "    } catch (std::exception& error) {\n",
+    "        std::cout << \"My own error handling : \" << error.what() << \"\\n\";\n",
+    "    }\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In the above, the normal expected path of the code start with a string definition, conversion of the string to a double, and then evaluation and printing of the cube root. If you run it the rest of the lines stay unused. But, if you then change the `inp` string to something that can not be interpreted as beginning with a number, `stod` can not fulfill its purpose. For instance, if you make `inp` into \"Frog\", there is no way to construct a `double` value out of the start of that string. The function `std::stod` then throws an exception. Once an exception is in flight, the program execution does not go line by line. It looks for the nearest enclosing `try` block. In this case, that's our `try` block. Program control looks for a `catch` block following that try block to see if the type of exception matches what is caught in the `catch` block. If it does, the code in that catch block is executed, and normal line-by-line execution begins from the `catch` block. If it does not match, subsequent `catch` blocks attached to the same `try` block are tested. In pseudo-code:\n",
+    "\n",
+    "```c++\n",
+    "std::string inp{\"3.14159\"};\n",
+    "try {\n",
+    "    auto num = std::stod(inp); // in case of error, throw something\n",
+    "    std::cout << \"Square root of \" << num << \" is \" << std::sqrt(num) << \"\\n\";\n",
+    "} catch (ErrorType1& error) {\n",
+    "    std::cout << \"Error : \" << error.what() << \"\\n\";\n",
+    "    std::cout << \"I will handle this by asking the user for input again\\n\";\n",
+    "} catch (ErrorType2& error) {\n",
+    "    std::cout << \"This other type of error has happened! I know how to fix this.\\n\";\n",
+    "} catch (ErrorType3& error) {\n",
+    "    std::cout << \"Error type 3 has happened! I will save useful data and quit\\n\";    \n",
+    "}\n",
+    "```\n",
+    "\n",
+    "Control jumps to the first `catch` block in the sequence that matches. If none of them do, the exception mechanism looks for the next higher level `try` block surrounding the current context, and tries to find a handler. If the exception remains unhandled all the way to the `main` function, the program terminates.\n",
+    "\n",
+    "Error handling with exceptions changes the execution flow of the program. The infrastructure required adds a non-zero cost to the program, even when no exception is thrown or handled. But then, run-time errors can be neatly handled to let the program recover from unexpected situations or save important results before closing gracefully. If your program is managing a self-driving car, letting it crash or misbehave due to unexpected inputs from sensors is just not a great plan!\n",
+    "\n",
+    "In summary, while exceptions are not zero-cost, the cost should really be compared to other ways of handling all sorts of errors. In most situations, the benefits of having exception-safety outweighs their measurable performance cost."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "C++17",
+   "language": "C++",
+   "name": "cling-cpp17"
+  },
+  "language_info": {
+   "codemirror_mode": "c++",
+   "file_extension": ".c++",
+   "mimetype": "text/x-c++src",
+   "name": "c++"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
-- 
GitLab