Skip to content

Commit

Permalink
Merge pull request #18 from MonashDeepNeuron/osman_writing_fixes
Browse files Browse the repository at this point in the history
Fixed errors in the first couple of subchapters in chapter 2
  • Loading branch information
oraqlle authored Oct 27, 2023
2 parents 09c5223 + deac97b commit 2a417a0
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/chapter2/condexpr.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Conditional expressions use the concepts of equality and ordering to allow progr

## Scope

One important concept in programming is the idea of scope. In C++, scope is very important as it can have an important impact on the design, performance in the safety of a program. Currently we have been running a program purely in the scope of the `main()` function. What denotes a scope in C++ is a pair of braces `{}`. Anything introduced within the braces is now in a new scope separate from the outside program. Objects from outside the new scope can be captured but anything created in a new scope is dropped at the end of the scope.
One important concept in programming is the idea of scope. In C++, scope is very important as it can have an important impact on the design, performance and the safety of a program. Currently we have been running a program purely in the scope of the `main()` function. What denotes a scope in C++ is a pair of braces `{}`. Anything introduced within the braces is now in a new scope separate from the outside program. Objects from outside the new scope can be captured but anything created in a new scope is dropped at the end of the scope.

```cxx
#include <iostream>
Expand Down Expand Up @@ -63,7 +63,7 @@ auto main () -> int

[Example](https://www.godbolt.org/z/4dK3P17ax)

We can also use an `else` clause at the end. This indicates that if and `if` expression fails, the `else` clause will execute instead.
We can also use an `else` clause at the end. This indicates that if an `if` expression fails, the `else` clause will execute instead.

```cxx
#include <iostream>
Expand Down
6 changes: 3 additions & 3 deletions src/chapter2/eqordlogic.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ auto main () -> int

## Ordering

Checking for equality is pretty straight forward. Some more interesting operations are the ordering operators. What is ordering? Ordering is a relationship of different values of the same type. Ordering is what gives numbers their sequence (`2 < 3`). Ordering operators allow use to check if some ordering condition is met.
Checking for equality is pretty straight forward. Some more interesting operations are the ordering operators. What is ordering? Ordering is a relationship of different values of the same type. Ordering is what gives numbers their sequence (`2 < 3`). Ordering operators allow us to check if some ordering condition is met.

- `<` - Less than
- `>` - Greater than
Expand Down Expand Up @@ -69,7 +69,7 @@ auto main () -> int

## Spaceships and Ordering Types

As of C++20 there as a new ordering operator introduced called the three-way-comparison operator or, the spaceship operator `<=>`. The spaceship operator different ordering types based on the strictness of the ordering.
As of C++20 there is a new ordering operator introduced called the three-way-comparison operator or, the spaceship operator `<=>`. The spaceship operator has different ordering types based on the strictness of the ordering.

- `(a <=> b) < 0` if `a < b`
- `(a <=> b) > 0` if `a > b`
Expand Down Expand Up @@ -155,7 +155,7 @@ In programming, it is useful to be able to check a multitude of Boolean expressi
- `&&` - Logical And
- `||` = Logical Or

Logical And and Or have special short circuiting properties. This means that the outcome of a Boolean expressions can be evaluated early. For And, if one Boolean point is `false`, it doesn't matter what the second point evaluates to as the expression's condition has already failed, thus whole expression would `false`. Inversely for Or, if one Boolean point is `true` the whole expression is true
Logical And and Or have special short circuiting properties. This means that the outcome of a Boolean expressions can be evaluated early. For And, if one Boolean point is `false`, it doesn't matter what the second point evaluates to as the expression's condition has already failed, thus the whole expression is `false`. Inversely for Or, if one Boolean point is `true` the whole expression is true

> Note: There is no logical Xor. This is because Xor cannot short circuited as the result depends on the result of both points. However, we have already seen the logical Xor, it is the `!=`. If the two points of `!=` are either both `true` or both `false`, the inequality condition is not met and thus achieving the exclusivity properties of Xor. In C++ because `bool` can be implicitly converted to other integral types, it is best that logicalXor is used as: `!(a) != !(b)`.
Expand Down
4 changes: 2 additions & 2 deletions src/chapter2/io.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ IO means input and output. IO operations are used to consume or emit data at the

## What is a stream?

What is a stream. A stream is a sequence of an indeterminate amount of data connecting a source to a destination. In C++, streams are used to connect a perform a variety of IO operations. You have already used on of these streams in C++, this is of course `std::cout`.
What is a stream. A stream is a sequence of an indeterminate amount of data connecting a source to a destination. In C++, streams are used to connect and perform a variety of IO operations. You have already used on of these streams in C++, this is of course `std::cout`.

## C Standard Streams

In C++ there are a few pre-defined stream objects. This are mounted to the the C languages `stdout`, `stdin` and `stderr`. These output devices are how C (and these stream objects) connect to the terminal screen and keyboard of your device.
In C++ there are a few pre-defined stream objects. These are mounted to the C languages `stdout`, `stdin` and `stderr`. These output devices are how C (and these stream objects) connect to the terminal screen and keyboard of your device.

- `std::cin` - Output stream to C's `stdin`
- `std::cout` - Output stream to C's `stdout`
Expand Down
8 changes: 4 additions & 4 deletions src/chapter2/operators.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Operators

Operators are unique symbols that are used to perform changes to data. They often have infix notation with some having prefix or postfix notation. In C++, all operators are functions however, they are built into the language fpr primitive data types.
Operators are unique symbols that are used to perform changes to data. They often have infix notation with some having prefix or postfix notation. In C++, all operators are functions however, they are built into the language for primitive data types.

## Basic Arithmetic

So enough about types and values. Lets write some code that does something. In C++ there are a lot, and I mean a lot of operators but we will only cover the arithmetic based one this week. The first ones we will look at are the basic arithmetic operators. These include your standard:
So enough about types and values. Lets write some code that does something. In C++ there are a lot, and I mean a lot of operators but we will only cover the arithmetic based ones this week. The first ones we will look at are the basic arithmetic operators. These include your standard:

- `+` - Addition
- `-` - Subtraction
Expand Down Expand Up @@ -148,7 +148,7 @@ In C++ there is another category of operators called bitwise operators. These op

> Note: We've seen `<<` before with `std::cout`. In the case of `std::cout` `<<` means 'put (to)'. It is simply an overloaded operator used for ease of use. It doesn't correlate to the bitwise meaning.
Each of the bitwise operators perform their respective logical operations on each of the bits the the two values or points and returns the new value.
Each of the bitwise operators perform their respective logical operations on each of the bits of the two values or points and returns the new value.

```cxx
#include <bitset>
Expand Down Expand Up @@ -253,7 +253,7 @@ Have a play with these operators and try and perform some computations that you

## Size Operator

Another useful operator is the `sizeof` and `sizeof...` operator. It returns the number of bytes if a type parameter pack (more on parameter packs later).
Another useful operator is the `sizeof` and `sizeof...` operator. It returns the number of bytes of a type parameter pack (more on parameter packs later).

```cxx
#include <iostream>
Expand Down
6 changes: 3 additions & 3 deletions src/chapter2/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ The first type we will look at is `bool`. `bool` represents a Boolean value, mea

### Character Types

The next type we will look is the `char`. This is C++ standard character type. These are values such as `'a'` or even escape characters like `'\n'`. It holds only a single byte (same as `bool`) allowing it to represent \\( 2^8 = 256 \\) different values. Depending on the system is is either `signed` or `unsigned`, meaning either the leading bit is dedicated to the sign of the value or is another number point. Depending on the representation, `char` can have a value between `0..255` (unsigned) or `-127..128` (signed). Character literals exclusively use single quotes in C++.
The next type we will look is the `char`. This is C++ standard character type. These are values such as `'a'` or even escape characters like `'\n'`. It holds only a single byte (same as `bool`) allowing it to represent \\( 2^8 = 256 \\) different values. Depending on the system it is either `signed` or `unsigned`, meaning either the leading bit is dedicated to the sign of the value or is another number point. Depending on the representation, `char` can have a value between `0..255` (unsigned) or `-127..128` (signed). Character literals exclusively use single quotes in C++.

There is another character type in C++ called `wchar_t`. This is a 'wide character' which can hold more bits than the `char` type. On Windows systems it is 16-bits (2-bytes) while on Unix based systems (Linux, macOS etc.) this is typically 32-bits (4-bytes). This allows for `wchar_t` to be to store many more different codepoints. A wide character literal also uses single quotes however, the quote pair is prefixed with a 'L' eg. 'a' as a `wchar_t` literal looks like `L'a'`.
There is another character type in C++ called `wchar_t`. This is a 'wide character' which can hold more bits than the `char` type. On Windows systems it is 16-bits (2-bytes) while on Unix based systems (Linux, macOS etc.) this is typically 32-bits (4-bytes). This allows for `wchar_t` to store many more different codepoints. A wide character literal also uses single quotes however, the quote pair is prefixed with a 'L' eg. 'a' as a `wchar_t` literal looks like `L'a'`.

Like `bool`, `char` and `wchar_t` are integral types, this means that they are really numbers however, the system will treat them differently, eg. for IO.

Expand Down Expand Up @@ -50,4 +50,4 @@ There are two more types in C++ that are worth talking about. These are `std::si

## Auto

While C++ is a statically typed language, it is able to infer and deduce the types of many things at compile time. This is achieve with a non-type keyword called `auto`. While `auto` is used in many places that type specifiers are used (more on this in the next section), it is important to note that it itself is not a type but rather a automatic type, essentially a placeholder for the to-be deduced type.
While C++ is a statically typed language, it is able to infer and deduce the types of many things at compile time. This is achieved with a non-type keyword called `auto`. While `auto` is used in many places that type specifiers are used (more on this in the next section), it is important to note that it itself is not a type but rather an automatic type, essentially a placeholder for the to-be deduced type.
10 changes: 5 additions & 5 deletions src/chapter2/typesystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,30 @@

## Strong vs Weak Typing

In [1.3 Hello World](../chapter1/helloworld.md) we discussed a bit about C++'s types system. But what is a type system? A type system is a formal notion of which terms have which properties. The rules and constructs of a type system underpin the meaning help by any discourse written in any and all programming languages. Without a type system, programming languages cannot construct grammar or structure and thus cannot become coherent and cohesive expressions of language.
In [1.3 Hello World](../chapter1/helloworld.md) we discussed a bit about C++'s types system. But what is a type system? A type system is a formal notion of which terms have which properties. The rules and constructs of a type system underpin the meaning held by any discourse written in any and all programming languages. Without a type system, programming languages cannot construct grammar or structure and thus cannot become coherent and cohesive expressions of language.

This is all a bit abstract and delves into [Type Theory](https://en.wikipedia.org/wiki/Type_theory) which is a more formal, mathematical notion of types. For our purposes we will just look at what C++'s type system does.

First and foremost, C++ is considered by many (but not universally) to be a strongly typed language. There isn't a universal definition of a strong or weak types but the basic premise is based around the question:

> Does the type system allow implicit conversions between type?
In the case of C++, 90% of types have no implicit conversions. The only contradiction to this is type promotion or narrowing, this is when types of the same _kind_ get promoted or narrowed to a similar yet different type. This occurs for some type in C++ because the bit width, layout and structure are so similar; due to how memory in computers work, that some types will implicitly meet the requirements of of another type. While this can occur in C++, it is limited to only a handful of primitive _data types_. Weaker typing allows for this implicit conversions to happen more frequently (think JavaScript's type system).
In the case of C++, 90% of types have no implicit conversions. The only contradiction to this is type promotion or narrowing, this is when types of the same _kind_ get promoted or narrowed to a similar yet different type. This occurs for some type in C++ because the bit width, layout and structure are so similar; due to how memory in computers work, that some types will implicitly meet the requirements of another type. While this can occur in C++, it is limited to only a handful of primitive _data types_. Weaker typing allows for this implicit conversions to happen more frequently (think JavaScript's type system).

## Static vs Dynamic Type Systems

So what about static and dynamic typing? These characterisations refer to the type checking techniques used in a language and how a language expresses the notion of types. These are the two key ways to look at either static or dynamic typing.

In a dynamically typed language, the type of an object does not have to be explicitly stated, but is inferred at runtime based on its contexts and the surrounding expressions. Python is a good example of this as you can create an object and assign it a type without ever declaring what type the object should be. This allows interpreters to forego type checking until a particular operation is performed on an object which may or may not fail. In a statically typed language, this is the opposite. You must formally declare the type of an object and i must be known to the system before the program ever runs. Most often, it must be known at compile time. However, some languages can forego an explicit **notation** of an object type and allow the compiler to infer the type. C++ and many other compiled languages; like Rust, are capable of type inference using various **argument deduction** techniques.
In a dynamically typed language, the type of an object does not have to be explicitly stated, but is inferred at runtime based on its contexts and the surrounding expressions. Python is a good example of this as you can create an object and assign it a type without ever declaring what type the object should be. This allows interpreters to forego type checking until a particular operation is performed on an object which may or may not fail. In a statically typed language, this is the opposite. You must formally declare the type of an object and it must be known to the system before the program ever runs. Most often, it must be known at compile time. However, some languages can forego an explicit **notation** of an object type and allow the compiler to infer the type. C++ and many other compiled languages; like Rust, are capable of type inference using various **argument deduction** techniques.

## A Pinch of Type Theory

Before we move on, there a some important definitions that are good to know going forward.

- Literals - A literal is a constant that refers to a determined value. For example, the character for 'three', `3`, has the value of three.
- Values - A value is the independent data of a type. Think of it as an instance or object.
- Types - A type is the formal definition and classification of values that is exhibit particular properties related properties. Examples of types include primitive data; like `int` from Python, as well as user defined types, often called classes in many languages. In C++ types are created using the `struct` and `class` keywords.
- Types - A type is the formal definition and classification of values that exhibit particular related properties. Examples of types include primitive data; like `int` from Python, as well as user defined types, often called classes in many languages. In C++ types are created using the `struct` and `class` keywords.
- Typeclasses - A typeclass is a polymorphic type constraint. It defines the expected properties of a type including methods, functions and patterns. In C++ typeclasses are created using the `concept` keyword.
- Kinds - A kind is, well; to put it bluntly, a type of a type. It describes the type of a nullary type constructor, ie. the constructor of primitive data-types which take no parameters. What this basically means is something that can hold a value.

In C++ supports everything except Kinds. We will go more into a little more depth during Chapter 5.
C++ supports everything except Kinds. We will go more into a little more depth during Chapter 5.
Loading

0 comments on commit 2a417a0

Please sign in to comment.