
On Sun, Dec 22, 2019 at 10:46 AM Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
On 22/12/19 9:04 am, Soni L. wrote:
switch (op) { [...] case OP_TAILCALL: { adjust_regs(); some_other_stuff(); /* fallthrough */ } case OP_CALL: { make_the_call_happen(); break; } }
Relying on fall-through in a switch is a micro-optimisation that may help make things go faster in C, but not so much in Python, so trying to find a literal translation is probably wrongheaded.
I would be inclined to separate it into two independent cases:
if op == OP_TAILCALL: adjust_regs() some_other_stuff() elif op == OP_CALL: adjust_regs() some_other_stuff() make_the_call_happen()
If the parts being duplicated are more than just one or two calls as above, I would factor them out into a separate function.
(You have the translation backwards here; a tail call should do three things while a non-tail call should do one.)
Decoupling the different branches makes the code easier to read and maintain, and in Python probably doesn't cost anything significant in performance.
It's not just about performance. It's also about expressing a concept. A tail call IS a call, and the correct way to write this is to do stuff, and then do whatever a call does. (Based on this implementation, of course.) "Refactor the common code into a function" isn't a solution to all problems, because if you have to go look elsewhere for the meaning of something, that stops you understanding it. It's hard to see in a trivial example, but the cost is very real in real code - unless you can give the refactored function a name that completely represents its purpose, all you've done is trade one form of hard-to-read code for another. ChrisA