In my opinion the best sequence looks something like this: - Machine language (not assembler) — Assembler for a couple of different architectures (i.e: Von Neumann vs. Harvard, CISC vs RISC, etc) - Forth (written from scratch with one of the above) - C - LISP - APL - C++ I think of everything else beyond these mostly as C/C++ cousins or derivatives. With languages like Javascript and Python it’s far more about learni…
- LISP / Scheme - Python - C - Assembler / machine - whatever else beyond here
maybe leave out the LISP depending on how religious one feels about it (I'm a fan, from a pedagogical approach at least).
Most students have a very weak understanding of what a computer does (i.e. Von Neumann arch, executing an infinite tape of instructions, etc). I like LISP / Scheme because it really helps bridge the gap between expressions (which students can pretty intuitively grok from high school math education) and it really has no language design warts; you can write a metacircular evaluator in ~10 lines.
Python is a next step because it goes from "how does coding work?" to "okay how can I do stuff with this?". The language itself is pretty straightforward (although certainly has its warts too, e.g. the odd methods of variable scoping), but there are a ton of libraries and it is pretty much useful straight away for anything one wants to design a course around. Many unis combine "learning Python" with programming some robot, doing an AI thing, or other such practical outcomes.
Importantly, whenever I taught a "relatively beginner Python course", I would always spend a huge amount of time on teaching students about ipdb / pdb. Allowing students to explore the state and stack of a running program is a critical doorway for them to step through to not only learn how to debug their own problems (less of a load on me!), but also really start to grok the "program is a sequence of instructions that change state" thing.
C before assembler, although I have found it's often useful to "combine" them so that the concept of a pointer seems less odd and more useful. Also, C still has tools that students can use to explore their code (e.g. gdb), whereas they're much more on their own with assembler.
After that, it really depends on what students want to do. They can stick with systems stuff and do Rust / C++ / Go or go to Javascript or go crazy with the PL stuff with Haskell, etc.
Certain people (perhaps yourself) really understand this "program is a sequence of instructions that mutates state" thing, but in my experience, most of my students really don't get that. If I were to throw them into that deep end of the pool where they lack the tools to debug their own problems, I would get a lot of bad reviews / people switching out of the major. On top of that, students often like to really be able to produce cool stuff, which they can in Python very easily. Many students may bounce off the lower level stuff if they just want to do front end too, which is perfectly fine in a "top down" approach from higher-level languages.