CALL and RET considered harmful.
The title of this post is a fun little jab at famous articles like “GOTO considered harmful“. A few years later Knuth’s “Structured Programming with go to Statements” provided a credible counterpoint. Knuth is famously quoted as saying we each develop “strong feelings” over these things because we are witnessing a revolution. So the takeaway is that both Djikstra and Knuth were expressing opinions that had not necessarily shown the test of time. Luckily we now have the test of time.
What is GOTO? What is CALL and RET? First of all, “GOTO” is a hard branch instruction like JMP. JMP sends the IP (instruction pointer) of the CPU to another location where code is then loaded from that point. CALL is extremely similar except that it pushes it’s location onto a stack, and then RET pulls this location off the stack and JMPs to it. In essence then, CALL simply creates a label (stores the location) and then RET issues a JMP to that location later on.
CALL and RET are convenience implementations which rely on JMP. This is your first clue that JMP, or shall we say GOTO, is not harmful. It is necessary, and all computers use it. So what is really going on here?
There is no spoon.
Why use CALL and RET when you can manually push your own location onto the stack and then by protocol (since you are writing RET at the end of a “routine”) — pop it and JMP to it? Why indeed. First, there is no reason why you couldn’t. There’s no reason you couldn’t even mix and match these protocols assuming one was essentially equivalent to the other. On many CPUs they are, in fact, essentially equivalent. This leads us to the first important point, “there is no subroutine”. Routines do not exist, they are a construct of the human mind. We create the idea of a subroutine, or a function, because by protocol, we assume that the return location is on the stack, because we have by protocol — by fiat — decided to structure our program this way.
However much ground we have gained from this point we now lose by admitting that CALL and RET serve a purpose of protocol, and therefore, JMP (or GOTO) does no longer serve this purpose, for this fiat.
For other fiat structures however, it may serve a purpose.
There is no fork, either.
Great noise is made about using goto to break out of nested loops. What about the break and continue commands, in C, perhaps? Well, what are the cons? Even in single loops. if you use a switch inside a for loop, what does break mean? Ahh, it is overloaded, so it’s use can sometimes be muted. Yes you could exit the switch and then break but that will be an extra conditional and a second break statement at the very least. Something which likely should have been handled inside the switch. Then there is the case of nested loops. If you use a variable as a break conditional and put the check in the for loop your wasting CPU cycles. If you check at every level it is a waste of space and cpu cycles. It is easy to speculate then, what about a “break n” command (where n is either the letter used in the for loop as the iterator variable, or, the level to break out of).
In any case, what have you have accomplished? You could have had a label at the end of the FOR loop — by protocol — by fiat — and then just JMP to it. Labels are free. Conditionals, variable, and so forth, are not. Even the compiler’s calculation of how to process a “break 3;” statement is not as free as a simple label.
There is no thing.
The point I am trying to make — and I could go on, but, the point is, there is no thing. Computers do not work like that. Take LISP for example. The idea of a recursive, bounded-on-both-sides, perfectly balanced functional programming language is an utter lie. It’s like RPN. People do not use RPN because people do not think like that. Our language does not work like that. People do not say I am hungry.. not. They say I am not hungry. Because when you have to think through a state whereby “I am hungry” but you’re not, and then you have to negate it, this is an un-natural method. Not just of thinking, but again, computers simply do not work that way.
Whatever “thing” you think you have come up with which is just so genius, think again. What you have done is tried to make a computer think like a human. But not just any human, you. Some arbitrary, strange notion you have about how data should be handled, or whatever, and you have tried to make the computer work like that. Well, they don’t, and they never will. And if you want to come up in the computer world, such constructs are in fact harmful. Even if languages like HASKELL were good (which they are not) you can never and should never learn them first. You should always learn how computers work if you want to be a programmer or a computer scientist. Anything else is folly.
What is there, then?
It’s true that we can have some nice things (abstractions). However many you want. Go, program in some functional language. Knock yourself out. Whatever. But notice the pattern. GOTO is considered harmful because we have established prototypes of structure by fiat, and going outside of those protocols, in fact, is what is considered harmful.
What small minds came up with this!
What if there was some new protocol we could come up with that would allow us to write better code? Faster and more efficient, for many reasons? Then it would be better.
Examples
Why save the CPU register state and then restore it at the end of a function? You may need to do this, but then again if you declared — again by fiat — a prototype or structure whereby some registers were free for local use — and that was your rule — it would be just as valid as any other rule. You could write faster, tighter code, which actually looks less like compiler spaghetti — facts.
Another example is, you could stop abstracting everything into functions and work with a state machine. For exampe, for traversing a tree, you could make a custom routine that traverses a tree in memory rather than by loading up variables and checking the index of the parent node and then pulling that and so on and so forth. You could chain jump from memory location to memory location. So fast. So small. Yes it’s for a dedicated purpose, but the work on your end is in the thinking. It does not take less or more time to type out; it takes more time for you to think in a different way, that’s all. But, thinking in this way is not for the new programmer.
So I say; Use your programming languages, but also free your mind; Spend some time on the other side. Using GOTO is not considered harmful, unless you are using it where other features of the language suffice. But if you know what GOTO is, what it really is, and how it is used, a whole new world of adventure has opened up before you. If you can, it is worth it to explore that world!
Filed under: Programming - @ April 30, 2023 12:10 am