1

I have seen What exactly is a reentrant function? and Reentrancy in JavaScript.

But still confused, it seems that reentrancy is something about concurrent, pure, and recursive. I'm not sure whether generator is a implementation of reentrancy, if so, what's the relationship between it and pure/recursive or other languages.

Hope your answer, thanks!

SmallTown NE
  • 543
  • 1
  • 7
  • 25
  • 1
    A pure function is always re-entrant, but that's about it. There's no special relation to purity. – Bergi Apr 15 '18 at 15:51
  • A re-entrant function is one that can be safely called even though a call to it has yet to complete. As @Bergi said, non-pure functions may be reentrant. In languages with shared-memory concurrency, functions can be reentered without being (directly or indirectly) recursive, but in an event-loop concurrent language like JavaScript, you won't see a non-recursive function reentered. But it's difficult in JavaScript to statically tell which functions might be reentered. – Mike Samuel Apr 15 '18 at 16:08
  • @MikeSamuel "but in an event-loop concurrent language like JavaScript, you won't see a non-recursive function reentered.", so, is generator a reentrancy function? – SmallTown NE Apr 16 '18 at 05:37

1 Answers1

4

Reentrancy means the same in JS as in other languages: A routine is re-entered when it is called again while it is still running. It's called reentrant when it is safe to do so (where "safe" is a really broad term, usually meaning "everything works still as expected") - or more formally, the function still fulfills its contract when called in that manner.

There are a few scenarios where this is relevant in JS (where a function usually runs to completion without being "interrupted" by something else):

  • The function is asynchronous. Parts of the two calls might run interleaved with each other. If that interleaving happens in a way the developer didn't expect, it's called a race condition.
  • The function takes (and calls) a callback. The user-supplied callback might call the function again.
  • The function is a generator function. It is called multiple times and the generators are consumed alternately.

A function that uses only call-local state (or is completely pure) is always reentrant. Things get messy when your function modifies global state, and especially when it does break the invariants of your data structures "only during the function call".

Here's a simple example of a non-reentrant generator function:

var k = 0;
function* countTo(n) {
    while (k < n)
        yield k++;
    k = 0;
}
for (const x of countTo(3))
    console.log(x);
for (const y of countTo(7))
    console.log(y);

Works, right? No, it doesn't, as k is a global variable here. Just consider

for (const x of countTo(3))
    for (const y of countTo(7))
        console.log(x, y);

Oops. The same functionality written as a reentrant generator function:

function* countTo(n) {
    for (var k = 0; k < n; k++)
        yield k;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I thought "safe" in this context referred to the function's contract, not a system or language level invariant. Something like "there are no contract violations that could occur when the function is reentered that could not occur when it is not." – Mike Samuel Apr 15 '18 at 16:11
  • Re "uses only local state", it might be worth mentioning that state closed-over by the particular function instance does not count as *local* in this context. – Mike Samuel Apr 15 '18 at 16:13
  • @MikeSamuel I think it's part of the contract of *every* function not to break system or language level contracts? But yes, I didn't think of the term "contract", that's a good idea. – Bergi Apr 15 '18 at 16:14
  • @Bergi Thanks for you response! I want to ask that how to think the term 'while' in "while it is still running". IMO, just those languages which support concurrent can do the 'while' thing, but in your answer seems you approval that 'generator' also is a re-entrant function. So I want to know whether 'while' means 'function context' or 'completely concurrent like mutil-thread'? – SmallTown NE Apr 16 '18 at 05:45
  • @SmallTownNE The context of the function for which the contract holds (like "a call to `countTo` produces all numbers from 0 to n" - another call to the function *while* it is still producing numbers should not interfere). The second implementation is reentrant, the first one is not. – Bergi Apr 16 '18 at 13:36