Well, I think you might also be grasping for some magic trick or concept as a way to avoid practice and study. You get better at programming and computational thinking by doing more of it. You write more software, and that’s part of what my advice of “lots of quick and dirty hacks” does. It forces you to write a full complete piece of software from start to finish, but doesn’t let you get bogged down in making it perfect. There really isn’t a magic trick to it. It just takes practice and work.
There’s only a few concepts in the simplest version of computation, so let’s try an experiment. I will explain them, and then you see if that somehow magically makes you better without any practice. Then, go get a piece of Python code from my book that has if-statements and while-loops and see if you can see all of these concepts in it. See if that helps. Then, write a piece of software but try to think about everything as these things:
Simplistic Computation
- A way to store and retrieve data.
- A way to execute instructions.
- A way to jump.
- A way to test.
- And let’s add a way to do input and output (because without that it’s all useless).
Storing Data
In the simplest form that’s just this:
x = 1
You can also go very bare metal in the CPU and do something like store into a register, but for now just act like the = is “store data”. It puts the data 1
into a spot in memory, and then gives it a name x
so you can use it later.
Retrieve Data
That’s just getting it back from memory using the name you gave it:
x
That’s it, so things like this works:
y = x + x + x + x
That’s 4 data retrieve and 1 store into y.
Execute Instructions aka The Tape
You then need a way to tell the computer to do stuff, and that’s instructions. In the CPU this can be thought of as a “tape” (think old school cassette tape) with instructions going in order. In Python this is just the lines of your file, so we could have this:
y = x
y += x
y += x
y += x
That is kind of like making a tape out of the larger line above so it is more like how a computer processes it. One single operation/instruction per line, and then think about the lines as having numbers so we can address them. This is important for the next ones.
Jumps
Just starting at the beginning of a tape and going to the end is kind of stupid. If you want to add 4 numbers, fine that’s a 4 instruction long tape (aka a 4 line long script). If we want to add a million numbers we’d need a million line script (million instruction tape). What we really want then is to loop over any set of lines, which is where a jump comes in. A jump just says, “go to line 3”, like this:
1: y = x
2: y += x
3: jump 2
That weird “jump 2” just means, “go back to line 2 and do it again.” It’s made up by me and not a real thing. That will just loop forever adding x to y, continuously increasing it. If Python that’s basically this:
y = x
while True:
y += x
Tests
A loop that goes on forever is pointless. I mean, sure, we’d like some kinds of software to run forever, but most of our loops should end. We also would need to make decisions on our jumps. That’s where tests come in, and that’s basically your classic boolean algebra tests:
y == 100
That just tests “is y equal to 100”, and returns true or false (or 1 or 0) depending on that equality. You can also do <=, >=, <, not, and many more.
Tests + Jumps == Logic
Typically though, when you do a test the result gets stored somewhere temporarily, so doing a y == 100 would put some kind of 1 or 0 into a “last test register”, which is just a small piece of temporary space.
If you have a way to test, and then jump based on that test, then you can do all the looping and if-statement constructs you want. Imagine this:
1: x = 1
2: y = x
3: y += x
4: test y != 100
5: jtrue 3
What’s that jtrue? It’s a thing I made up that stands for “jump if iftrue”, and kind of comes from assembly language. It’s like saying, “if the last test results in true then go to line 3”. And remember my made up assembler the test
tells it to do the boolean test y == 100
and then record if that was true (1) or false (0).
I could kind of pythonify that with this:
1: x = 1
2: y = x
3: y += x
4: if y != 100: jump 3
Now, what do those chunks of code do? Well, this:
x = 1
y = x
while y != 100:
y += x
What about if-statements? Let’s say I don’t know what’s in a variable p
and need to decide something:
1: test p < 100
2: jtrue 10
3: # greater than 100 code starts here
...
9: jump 11
10: # less than 100 code starts here
11: # code is done so we jump here to get out of this test
This is a simple if-else like this:
if p < 100:
# less than 100 code starts here
else:
# greater than 100 code starts here
But as with a lot of CPU code we have to invert it because we only have jumping and not kind of fancy nested constructs like with Python’s if-else.
Input and Output
Finally, with all of that we need a way to read in some data and write it out. That’s usually done as input and output, so if I took the above if-statement and had an read
and write
instructions I could do:
1: read p
2: test p < 100
3: jtrue 6
4: write "That number is greater than 100."
5: jump 7
6: write "That number is less than 100."
7: # continue with the code
Already this is getting nasty but it’s kind of fun. We have to figure out how to do tests, and then jump over lines and also jump over the other lines from there. In Python the above code is:
p = input()
if p < 100:
print("That number is less than 100.")
else:
print("That number is greater than 100.")
You can see why we kind of stopped bothering with this raw machine code because it gets really hairy even in simple cases like this. BUT, with just these 5 things you can actually do all of the programming we have right now (although really horribly). At least I think so. I might be missing something but this should cover everything.
Concepts to Application
Alright so you now have the 5 things that are at the center of all computation. Since I can tell that you’re hoping for something like this I suggest you take it and analyze it, and then see if you can break down a very small Python program into this fake CPU language I have here. Then try the reverse and convert a fake CPU into Python.
Once you do that, see if you can find these concepts being used everywhere. Then, it’s time to blow your mind out of the water with this:
https://docs.python.org/3/library/dis.html
THAT is basically Python’s fake assembler code. Try using that to dump the contents of simple functions and see if you can figure out what they do. There’s a complete list of Python’s instruction set. So, maybe learning that will help you figure out what’s going on and start to feel more confident in what you’re writing.