foo() { foo(); }
foo() { foo(); }
results in a repeating stack:
foo()
foo()
foo()
...
the cure for infinite recursion is figuring out under what conditions
the recursive call should not be made (
if (stop) return; else
foo();
).
it can
be a challenge to figure out this condition, but you still only have to
examine a single procedure to do so.
write reviews for amazon and get free stuff
mutual recursion makes the story more interesting still. what happens
when you have
foo() { bar(); }
bar() { foo(); }
is that you have a repeating stack, but with period 2 instead of 1:
foo()
bar()
foo()
bar()
...
repairing infinite mutual recursion is harder than repairing simple
recursion
because you have more options. the problem could be in
foo()
,
in
bar()
, or in the relationships between the two. which
one needs fixing? at what point does the computation have the
information needed to forgo yet another call?
write reviews for amazon and get free stuff
in
the saff squeeze i started to
explore the joys of inlining code. i have the sense that there is a lot
more to inlining than i have figured out so far. nearly every day i
program i find a new use for it, now that i'm paying attention. it is
an excellent tool for exploring, understanding, and manipulating
complicated control flows. i'm not ready to write the grand unified
theory of inlining yet, but responding to non-terminating object
programs turned out to be a good application of inlining. here's how it
works.
spotting infinite recursion is relatively easy in the case of a single
procedure:
foo() { foo(); }
. inlining transmutes the
mutual recursion case into simple recursion. if i inline
bar()
from
above
i get
foo() { foo(); }
. the source of the infinite
recursion is clearer. once the code is working i can always re-extract
subprocedures that communicate clearly.
inlining in the service of debugging applies the "make it run, make it
right, make it fast" mantra in reverse. if my code doesn't run, making
the design worse through inlining isn't a sin if it helps me fix the
defect. the additional insight i gain from making the code work in more
cases often helps me further improve the design when the time comes to
"make it right" again.
objects make spotting non-terminating computations even more exciting
(by which i mean "tedious and frustrating"). the periodicity of the
stack can be long and is complicated by the potential presence of many
different classes and objects as well as methods:
a.b()
c.d()
e.f()
a.b()
c.d()
e.f()
...
sometimes the instances of a, c, and e are the same objects every time
through the loop, sometimes they are different but somehow equivalent
instances (at least as far as loop termination is concerned). the
longest cycle i've seen is six frames long, which makes spotting
the pattern tough. fortunately, since the computation is infinite you
can easily make as many frames as you need to provide yourself data for
identifying the loop :-)
when i've run out of stack space and spotted the cycle, how do i figure
out the problem? since inlining is my trick du jour i
suggest
inlining. inlining works across objects just as well as it does across
procedures, although you may have to temporarily make fields and
methods public to keep everything working. (always take a snapshot of
the state of the code before starting one of these sessions--you'll
likely make lots of ugly changes that become irrelevant once you figure
out
how to fix the problem. i say this because we didn't take a snapshot...)
we picked the entry point of the infinite cycle and started inlining.
eventually we got a method that looked like
a.b() {...b();...}
.
we could see
exactly why the cycle wasn't terminating. what still wasn't clear to us
was what to do about it. just seeing the cycle clearly seemed like
progress, though, and worth writing up.
in fixing a non-terminating object program you have a couple of
options: break the cycle or don't get into the cycle in the first
place. for our code, i suspect not getting into the cycle in the first
place was the right idea, but we didn't have time to explore this
option once
we'd identified the problem logic.
write reviews for amazon and get free stuff
one of the things that struck me while we were working was the
connection between inlining and partial evaluation. i wonder if
revisiting the literature on partial evaluation would provide further
ideas for the applying inlining or tools for making inlining more
effective.
another point that struck me was how infrequently this situation
occurs. is it even worth thinking/writing/learning about
non-terminating object programs if they only happen to you once a year?
i think the answer is "yes" (obviously, and i suppose if you've gotten
this far you likely agree). multi-object infinite loops are a hard
problem to solve. it seems like there is always some ugly hack
available to break the cycle, but one that is unlikely to satisfy
future conditions. having a clear plan for understanding infinite
cycles gives me a chance to step back and really understand the
situation and what should be done about it, to design, not just make an
expedient coding change. that is how i aspire to work, and if exploring
situations that happen infrequently is the cost of thoughtful
development, i'll pay it.
if you try this inlining technique to understand an infinite cycle,
please
let me know
how it goes. happy debugging. and designing.
- how to get paid for reviews on google 2023/12/4 18:00:33
- 100 5 star fake reviews amazon 2023/12/4