"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."
"// 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": null,
"id": "military-danger",
"metadata": {},
"outputs": [],
"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": null,
"id": "humanitarian-carter",
"metadata": {},
"outputs": [],
"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) {// Since 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": null,
"id": "reduced-warehouse",
"metadata": {},
"outputs": [],
"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",
" 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",
"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",
"Let's explore namespaces by creating some on our own."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "retained-difference",
"metadata": {
"tags": []
},
"outputs": [],
"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": null,
"id": "educational-effort",
"metadata": {},
"outputs": [],
"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."
"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": null,
"id": "heavy-frame",
"metadata": {},
"outputs": [],
"source": [
"// If you uncomment the following lines and run this cell, you would have to restart the kernel\n",
"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": null,
"id": "danish-cabin",
"metadata": {},
"outputs": [],
"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."
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,
```c++
if(x>1){
x=sqrt(log(x));
std::cout<<"x decreased to "<<x<<"\n";
}else{
x=1;
std::cout<<"x clamped to 1\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.
The top level block is always the body of a function.
Although blocks are frequently used to organize code around `if` statements, loops etc., blocks can stand on their own. Anywhere in a function,
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.
// Since the variable names ship and destinations were not defined outside the block at the top, we were free to define and use
// them for any purpose we need! Here we created integers with those names.
```
%% Cell type:markdown id:honey-aspect tags:
```c++
if(argc>1){
autoN{stoi(argv[1])};// N is an integer
}else{
stringN{"Navoo"};// N is a string
}
cout<<N<<"\n";// Error! N is not defined.
```
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 id:military-danger tags:
``` C++
{
auto argc = 2;
if (argc > 1) {
auto N { stoi("224") }; // N is an integer
} else {
string N { "Navoo" }; // N is a string
}
// cout << N << "\n"; // Error! N is not defined.
// What (declarations) happens in a block, stays in that block
}
```
%% Cell type:markdown id:floating-sociology tags:
## Scope of a declaration
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
- for a variable declared in a block, the scope begins with its declaration and ends at the closing `}` of the block
- for a variable declared in the header of a for loop, its scope is the loop body
- for variables declared along with the condition in an `if` statement: both `if` and `else` part of the conditional branch
- for variables declared in the function header, the scope is the function body (later!)
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 id:humanitarian-carter tags:
``` C++
int i = 0, j=1;
while (j < 1000) {
// if (i > 0) cout << "old value of sum = " << sum << "\n";
// If you uncomment the above, it will be an error
auto sum = i + j; // scope of sum begins here
i = j;
j = sum;
cout << i << "\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 tags:
```c++
for(inti=0;i<N;++i){
//counter i defined only in this "for" loop.
}
doublenewval=0;
for(inti=0;i<N;++i){
// The counter i here is a different entity
if(newval<5){// same newval as 3 lines earlier
stringfl{"small.dat"};
// do something
}// fl dies here!
newval=...;
cout<<fl<<’\n’;// Error! The name fl is not defined here!
}
intfl=42;// ok
if(autof=filename;newval<5){// Since C++17
// f is available here
}else{
// f is also available here
}
```
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 tags:
### Name visibility in nested blocks
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 id:reduced-warehouse tags:
``` C++
int s1{1}, s2{2}, s3{3};
if (s1 < s3) {
// s1, s2 and s3 are visible here, because they were visible at the opening { of this block
std::string s3{"umbrella"}; // A new block-local s3 comes in and "shadows" the outside s3
cout << "line 5: " << s1 << "\t" << s2 << "\t" << s3 << "\n"; // s1, s2 from before, s3 from the block
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
} // The s3 declared inside the block dies here. Shadow lifts!
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++.
The following is a conversation I never had, but I could have had!
### Imaginary conversation...
A: "Thomas Müller is in this building."
B: "The football player ?"
A: "Yes, I guess, he plays football. Sometimes. Quite possibly."
B: "In the German national team ?"
A: "No, not that one. I meant the scientist working in the computational science (CS) division at the Jülich Supercomputing Centre (JSC)."
B: "So, you meant, JSC :: CS :: Thomas Müller !"
- A **namespace** is a named context in which variables, functions etc. may be defined
-`::` is called the **scope resolution operator**
- The statement `using namespace blah` imports all the names in the namespace `blas` into the current scope
```c++
// Somewhere in the header iostream
namespacestd{
ostreamcout;// Definition of a variable called cout with the useful property that lets us write things on the terminal
// << is an operator in C++, like +, -, *, /
// When we use << with a variable of type ostream on the left and something else on the right,
// that other thing gets written to the screen. ostream is a library provided class, and you will
// see, we can control the behaviour of operators when class types are involved. Later!
// The definition of the variable cout sits inside the namespace std
}
// In your program ...
#include<iostream>
// A variable called std::cout is now visible
automain()->int
{
{
usingnamespacestd;
// All names defined in the namespace std are visible. Therefore std::cout can now be
// addressed by its plain name, cout
cout<<__func__<<"\n";
}// Visibility of the names imported by the using namespace declaration ends here!
intcout=0;// This cout is just an integer
for(cout=0;cout<5;++cout)
std::cout<<"Counter = "<<cout<<’\n’;
// Above, plain cout is an integer,
// but std::cout is an output stream
// The syntax to refer to a name
// defined inside a namespace is:
// namespace_name::identifier_name
}
```
%% Cell type:markdown id:stupid-madonna tags:
Let's explore namespaces by creating some on our own.
%% Cell type:code id:retained-difference tags:
``` C++
#include <iostream>
#include <string>
namespace UnitedKingdom {
std::string London{"Big city"};
}
namespace UnitedStates {
std::string London{"Small town in Kentucky"};
}
using namespace UnitedKingdom;
// You can not rerun this cell without restarting this kernel. That's why we isolated
// the namespace part to its own notebook.
```
%% Cell type:markdown id:liable-sierra tags:
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 id:educational-effort tags:
``` C++
std::cout << London << '\n';
std::cout << UnitedStates::London << '\n';
```
%% Cell type:markdown id:italian-theology tags:
Let's reopen the `UnitedKingdom` namespace and add a new variable to it.
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 id:heavy-frame tags:
``` C++
// If you uncomment the following lines and run this cell, you would have to restart the kernel
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 id:danish-cabin tags:
``` C++
#include <iostream>
namespace USOH = UnitedStates::OH;
std::cout << "London is " << USOH::London << '\n';
// This is valid code, has been valid since C++11. But the cling interpreter does not support this.
// The error message you get is also meaningless. Observe the syntax above and use it.