Teaching Programming Languages by Experimental and Adversarial Thinking
cs.brown.edu
cs.brown.edu
[Edit: I guess this is just the link on HN. So just providing a reason why it's also useful.]
Yes, I know about the problems w/ security through obscurity, etc.
So for now, it's only an in-person course at Brown (and a few other universities that have been picking up this approach).
Sorry, I know, it sucks. But I don't know of a better solution that satisfies all constraints.
For the 2017 course [1] we re-implemented the mystery languages in Racket, so you'll need to install DrRacket to use them. But they're a bit improved and more robust.
That includes teaching the very point you're talking about. There is nothing in the mystery language approach that precludes having programs whose behavior is non-deterministic, and this would then show students to prepare for it. Indeed, it's an excellent kind of mystery language, by providing a sandboxed version that can focus precisely on non-determinism.
(I will not reveal whether such behavior exists in the current suite or not, to avoid giving away solutions.)
With older compilers, the usual question is "Will `-2 >> 1` perform sign extension or not?" With modern compilers, the usual question is "What arbitrary constant can the compiler choose for `-2 >> 1` to maximize the number of provably dead code paths?"
Students can then move on to C/C++ using a different approach, but already having learnt most of the concepts.