the_website icon indicating copy to clipboard operation
the_website copied to clipboard

Order of lessons

Open Xeverous opened this issue 4 years ago • 15 comments

This is one of the hardest things to figure out (at least for me). This issue is intended to discuss the problem and list any noticeable things that could help in making better lessons order. Post your suggestions in this issue.

Current/planned order:

beginner C++ tutorial

  • intro
    • basic terms (compiler, linker, shell, IDE, etc)
    • incremental build systems
    • runtime errors vs build errors
    • static vs dynamic libraries
  • functions
    • overloading
    • default arguments
    • = delete
  • structures
    • default initializers
    • composition
    • aggregates, aggregate initialization
  • multifile projects
    • inline
    • anonymous namespaces
    • inline namespaces
  • classes
    • ???

C++ templates tutorial

  • functions
    • basics
    • instantiation
    • deduction
    • overloading
    • default template parameters (this late?)
  • classes
  • SFINAE
    • intro
    • std::enable_if
    • std::void_t
    • writing type traits on SFINAE

Notes:

  • Pointers needs to be as late as possible. They confuse beginners and are rarely used in high-level C++ code. They are a major cause of frustration and fighting with the compiler.
  • Classes depend on functions.
  • Lambdas depend on functions.
  • Exceptions depend on classes.
  • When to introduce multifile code? Should this be a separate chapter or should the content be blended with other?
  • Multifile code should be before classes. If the chapter is very late, it will be just a boring list of how to split every possible entity definition from declaration.
  • Should the beginner tutorial cover topics like debugger and testing (built into lessons) or should they be separate articles?
  • Enums should be before classes. They are simpler uder-defined types.
  • Most convertions (except dynamic_cast) should be before classes.
  • Functions: overloading vs default arguments - which first?
  • Operator overloading requires to explain *this as lots of canonical implementations do stuff like return *this;.

Xeverous avatar Jun 05 '21 12:06 Xeverous

I think that it may be a good idea to only introduce build systems in the beginning, just to get started, and then delay a more extensive discussion until later. The reason for this would be that build systems can be a dry topic and you want people invested in the language before you get into the weeds. Same with static and dynamic libraries.

With regards to overloading and default arguments, I can see a case for default arguments purely based on the fact that they are common in other programming languages.

hasref avatar Jun 06 '21 16:06 hasref

The reason for this would be that build systems can be a dry topic and you want people invested in the language before you get into the weeds.

Definitely this. There is delicate balance between build systems introduction and explaining all of the compiling and linking process (which is quite complex and platform-dependent). Not enough and the reader will get lost in setting up the environment. Too much and the reader will be bored.

I think more detailed statements can be made once the project gets more content and some examples. Only then we can make a conclusion what is necessary to briefly explain and what can be presented in an in-depth chapter about building.

With regards to overloading and default arguments, I can see a case for default arguments purely based on the fact that they are common in other programming languages.

This is a pretty trivial issue. I think it will simply boil down to what examples I can come up with. Default function arguments are more or less a simplified way of overloading so defaults will probably be first and then overloading can be explained starting by showcasing code equivalent to previous default arguments.

Xeverous avatar Jun 06 '21 17:06 Xeverous

I would think the order for a complete beginer should be something like:

Environment setup

Something really simple, you want them coding, nothing else. Here you end with a hello world just to test that what they have works, tell them you will explain it latter.

Hello world

Explain it line by line.

Dont get into too much detail into questions like "What does #include<iostream> mean?". Dont give a long explanation, tell them that more details will come latter.

Out of here they will know how to ouput text, and will have the following template to use.

#include <iostream>

// using namespace std; <-- Im not sure of including this line. 

int main() {
    // Your code goes here
    return 0;
}

Types

List the basic ones. (int, float, etc. Dont get into containers yet)

Variables

Give just a general idea. Start making emphasis on good names.

Reading user input

Out of this one they can read input from the user and output it.

Operations on the data

+, -, /, *, etc.

Now they can make basic operations on the data. Here is where you could start to intoduce some small problems for them to solve. You could have a space for them to upload their code, run it with the piston api, and check the result (Tell me if you need help implementing this).

Flow control

Conditinals

Loops

Functions

Anonymous functions

Lambdas including a light introduction into <algorithm>

Overloading

More types

Standard library containers and references.

Light introduction to std::string, std::array, std::vector.

Some qualifiers

static, inline, const, constexpr etc.

Give them a general idea of them, and make a big enfasis on const and const correctness

Error handling

Exceptions depend on classes.

I disagree, you could introduce exceptions, and tell them how to implement their own latter.

Talk a bit about noexcept

class

Intro to OOP

struct

It does not need to be too long, just tell the diference, and say that it is there because of C.

Inheritance

Now you can tell them how to make their own exceptions.

Pointers

Dynamic memory allocation, smart pointers and RAII

Namespaces


And they sould have a general idea of the language. Then have a section to go into more detail.


Operators, and operator overloading

Now they have their own types, let them overload some operators for it.

Functors

The compilation process

More of the STL

More containers, iterators, algorithms, etc.

Templates

Desing patterns using templates

constexpr

Now give them a full guide.

Tools

Introduce tools like clang-tidy.

Build systems

Mulitple file proyects

Conventions

Testing

Specifically unit testing

The core guidelines and the GSL


We would end up with something like:

  • Environment setup
  • Hello world
  • Types
    • Variables
  • Reading user input
  • Operations on the data
  • Flow control
    • Conditinals
    • Loops
  • Functions
    • Anonymous functions
    • Overloading
  • More types
  • Some qualifiers
  • Error handling
  • class
    • struct
    • Inheritance
  • Pointers
  • Dynamic memory allocation, smart pointers and RAII
  • Operators, and operator overloading
  • Functors
  • The compilation process
  • More of the STL
  • Templates
    • Desing patterns using templates
  • constexpr
  • Tools
  • Build systems
    • Mulitple file proyects
      • Conventions
  • Testing
  • The core guidelines and the GSL

Im pretty sure im missing something, but im not sure what.

Polo123456789 avatar Jun 07 '21 19:06 Polo123456789

[includes] Dont give a long explanation, tell them that more details will come latter.

Agree. Initial explanation will briefly cover why it's needed. Entire preprocessor can be explained later in a specific chapter.

using namespace std; <-- Im not sure of including this line.

The answer is no. There are multiple reasons:

  • Even if for the currently written program it is justifiable, beginners tend to stick to it. This is very slippery and once they have gone too far, stopping this habit is a huge hit.
  • That's not really a thing you see in production code. At most locally within function scope, often just selective using (e.g. using std::string).
  • I have many examples which use functions with the same naming as standard library ones. The using would create name conflicts.

I will probably even write a short warning that a lot of tutorials do it and why it's bad.

You could have a space for them to upload their code, run it with the piston api, and check the result (Tell me if you need help implementing this).

Environmental setup is for it so that readers can easily copy-paste programs from the site and run them on their own. I don't see any significant value in offering beginners online compilers.

The core guidelines and the GSL

This content is much better done at every possible moment rather than a full "lesson" on its own. If someone want that all-in-one lesson, they should just go to Core Guidelines page. IMO it's much better if I mention best practice + common mistakes right at the point where a given feature in introduced. Some readers like to go back to previous lessons if they feel they forgot something and placing specific guidelines inside lessons just feels worthwhile.

Im pretty sure im missing something, but im not sure what.

The full "list of lessons" would be a graph with ~200 elements (each being a short explanation, multiple ones per lesson) where there are multiple questionable dependencies. I might draw this graph at some point and attach a rationale to each dependency.

Other notes:

  • I'm a bit surprised how early you propose lambdas. On the other hand it allows a very early introduction into <algorithm> which is great. This will be needed to be worked out - perhaps the graph can help.
  • Functors - I have recently got a message that "functor" is a very specific functional programing term and it does not match it's usage in C++. "function object" is correct and self-explanatory.
  • Multiple file projects - IMO you propose them to be too late. Such chapter should be done roughly early (some time after functions, which already need to introduce forward declarations), otherwise if it's done very late (e.g. after classes) it's a big hit for the reader to remember where everything goes (this is not that simple - just think of default arguments, static, inline, attributes, override, ...). I would favor learning it on-the-go some time after functions have been introduced.
  • Error handling - in theory exceptions could be introduced as soon as functions and the call stack is explained, but I'm not sure if there aren't more valuable topics at this time. I'm only sure that the chapter can get some really good examples - maybe these will help figuring out what's needed and when.

Xeverous avatar Jun 07 '21 22:06 Xeverous

Environmental setup is for it so that readers can easily copy-paste programs from the site and run them on their own. I don't see any significant value in offering beginners online compilers.

My idea was to use for testing. They upload their code, and you tell them if their answer is correct. Will allow you to have a good list of test cases.

This content is much better done at every possible moment rather than a full "lesson" on its own.

True. My idea was to give them good habits during the whole tutorial, and at the end mention the core guidelines, because you cant cover everything in the tutorial.

The full "list of lessons" would be a graph with ~200 elements (each being a short explanation, multiple ones per lesson) where there are multiple questionable dependencies. I might draw this graph at some point and attach a rationale to each dependency.

Im looking forward to that.

Polo123456789 avatar Jun 07 '21 23:06 Polo123456789

[The graph] Im looking forward to that.

This could be a separate project on it's own... It could significantly help in figuring out order of lessons but I really need a tool for doing such fancy graph stuff (best in the form of automated script that reads file with the input).

Xeverous avatar Jun 07 '21 23:06 Xeverous

@Polo123456789 do you have any idea when to explain RAII? I get conflict of interests:

  • RAII naturally feels it should be in classes chapter but explanations basically seem to require pointers, unless I find a reasonable pointerless resource to manage
  • pointers should be as late as possible, preferably even after polymorphism

Xeverous avatar Jun 08 '21 21:06 Xeverous

Pointers aren't inherently bad. Any specific reason why you want to teach them as late as possible?

Polo123456789 avatar Jun 09 '21 00:06 Polo123456789

They aren't inherently bad but they are inherently complex.

Reasons listed in Kate Gregory - Stop teaching C talk:

  • At early states, beginners are still learning to remember the syntax. Pointers have significant syntax impact.
  • Pointers require significant leap in thinking, something which is better done later when people know more how the language works underneath. Otherwise they won't get the idea and you will end up with them treating it as vodoo randomly inserting * and & into code untill compiler agrees.
  • You can go as far as explaining polymorphism without use of pointers.
  • Pointers are major cause of frustration, yet you don't really use them often in modern C++. High risk + low reward.

Other reasons:

  • It's a teaching trap: thinking that you need to explain underlying mechanisms before explaining higher level concepts. Python proves you don't need to understand pointers in order to write code, yet so many "teachers" insist on teaching C as a prerequisite to C++ (as if you needed to learn latin before english). People use many devices every day (dishwasher, microwave, fridge, ...) without understanding in detail how they work - they just need to understand the interface (buttons).
  • K&R book "The C programming language" has pointers at half of the book. And it's just C. With C++ we can push them even later.

Xeverous avatar Jun 09 '21 08:06 Xeverous

I would disagree, because I think at that point they are ready to learn about them but, at the end is your project.

If the problem was:

RAII naturally feels it should be in classes chapter but explanations basically seem to require pointers, unless I find a reasonable pointer less resource to manage

One that I could think of requires threading. You could talk about mutexes and make them implement their own std::lock_guard.

From RAII in cppreference:

std::mutex m;
 
void bad() 
{
    m.lock();                    // acquire the mutex
    f();                         // if f() throws an exception, the mutex is never released
    if(!everything_ok()) return; // early return, the mutex is never released
    m.unlock();                  // if bad() reaches this statement, the mutex is released
}
 
void good()
{
    std::lock_guard<std::mutex> lk(m); // RAII class: mutex acquisition is initialization
    f();                               // if f() throws an exception, the mutex is released
    if(!everything_ok()) return;       // early return, the mutex is released
}      

Polo123456789 avatar Jun 10 '21 22:06 Polo123456789

I would disagree, because I think at that point they are ready to learn about them but, at the end is your project.

Ready does not mean optimal for.

My current plan (still quite tentative)

  • classes chapter (member functions, access specifiers, const, mutable, constructors)
  • operator overloading chapter (a page for each set of related operators)
  • inheritance & polymorphism chapter
  • pointers chapter
  • RAII chapter (destructors, copy/move ctors, copy/move assignment)

RAII is extremely important in C++, but I think that beginners don't need to understand it that early because before pointers chapther all code they will write will use rule of 0. RAII only makes sence once there is some resource to manage and for that I would really want pointers.

What do you think of this order?

Xeverous avatar Jun 10 '21 23:06 Xeverous

Seems ok.

Polo123456789 avatar Jun 11 '21 16:06 Polo123456789

I have hit a somewhat dead end in ordering and it's really hard to write pages without knowing what can be assumed that the reader knows.

The current plan is to use Graphviz to generate a graph of all lessons and find dependencies between them. This is going to take some time but it should be a very valuable resource. Plus the same software can be later integrated into website build process - it would be awesome to draw graphs explaining stuff like pointers and data structures.

Xeverous avatar Jun 14 '21 14:06 Xeverous

Writing now a year later, the project has got significant progress. The current order of chapters in the core tutorial is:

  • 01 - start (optional knowledge like binary system, why there are multiple programming languages and so on)
  • 02 - basics (syntax, comments, types, literals, operators, identifiers, objects)
  • 03 - control flow keywords
  • 04 - functions (including overloading, constexpr, recursion, references)
  • 05 - preprocessor
  • 06 - some additional stuff (namespaces, static, extern, inline, maybe also modules)
  • 07 - arrays
  • 08 - streams (more how-to than actual language feature knowledge) (states, formatting, files)
  • ?? - some unsorted stuff to be put somewhere earlier (enum, struct)
  • [...] possible intermediate chapters (lambdas, STL, more how-to chapters like streams)
  • xx - classes (members, access, ctors, const, mutable, explicit, static, friends)
  • xy - operator overloading

Notes:

  • 05 - I'm quite satisfied with the placement of the preprocessor chapter. Putting it at the start would be very boring and dissatisfactory for readers (explaining internal language problems) but at the same time I don't want to have it too late. Placing it after functions guuaranteed enough knowledge (especially ODR and declaration vs definition topic) and let me use good examples why code would be split across files.
  • 06 - The chapter after preprocessor continues the topic by explaining stuff like linkage and storage duration. This is also a rough place where I would put future lessons about modules.
  • xy - operator overloading should be right after classes. The chapter itself is more of a reference than actual learning (it just explains canonical implementations for specific operators). The content is very easy and allows me to mention few related topics (user-defined literals and user-defined convertions)

Right now, the biggest tension in regards to the order is RAII vs inheritance/polymorphism. The reasons are:

  • RAII essentially requires pointers. I would like a dedicated separate tutorial serie for this topic (pointers, functions pointers, member pointers, RAII, alignment, packed structs, extern C and everything else "low-level"). I would like to avoid pointers in the main tutorial serie, especially because I would like it to be for both C++ newcomers and people with experience in other languages. Being able to assume that the reader understands a lot of other stuff will make explaining pointers much easier.
  • Inheritance/polymorphism itself doesn't require pointers but there is a strong pressure for something additional in examples. You need things like std::vector<std::unique_ptr<base>> to truly showcase dynamic dispatch and other mechanisms. Kate in her talk "Stop teaching C" says people will understand virtual functions very easily, even without any prior pointer knowledge. I just feel the quality of articles will be damaged if I can't showcase richer examples and need to use some "magic" like standard library smart pointers to have an array of dynamic types.
  • Inheritance has a lot of language rules and guidelines that are related to special member functions (copying base classes, object slicing, destruction order, virtual destructors)

Something must be choosen. Currently I'm more inclined towards separate tutorial for RAII and focus on good OOP in the main tutorial, potentially with reduced explanations on some stuff that involves resource manegement. It would be very good if someone could share their teaching experience. I also need good examples for pointers and inheritance topics.

Xeverous avatar Apr 15 '22 16:04 Xeverous

After looking at the talk again (specifically 25:39 - 29:27), it's clear that polymorphism can be done before pointers and all the RAII stuff.

Xeverous avatar Apr 16 '22 09:04 Xeverous