Strange behavior for Python code that uses first-class functions


#1

As I was working on The Trials, I thought of a way to abstract out the notion of finding the nearest entity of a particular type, dealing with it, and then finding the next until all entities were removed. So I came up with the below code… but the compiling message never goes away, and I eventually get the message that “Code never finished,” with none of the entities in the game world doing anything and no time elapsing in the timing bar.

def processAll(find, act):
    all_of_them = find()
    while len(all_of_them) > 0:
        nearest = self.findNearest(all_of_them)
        act(nearest)
        all_of_them = find()
        
def kill(enemy):
    while enemy.health > 0:
        self.attack(enemy)

def pickUp(item):
    self.moveXY(item.pos.x, item.pos.y)
    
processAll(self.findEnemies, kill)

processAll(self.findItems, pickUp)

Please cross-reference What’s going on with Python closures?. My problem is not quite the same as dzhang314’s problem, in that I’m not actually returning a function from any functions, but in both cases we’re passing functions around, so I suspect that the same weakness in the compiler is involved.

EDIT: I should note that I also tried doing the following, suspecting that the root of the problem might be that Python self is directly translated to this when cross-compiling to Javascript, and Javascript (if I recall correctly) has an issue where this only refers to the object to the left of the period at the call site, making it impossible to directly pass instance methods around.

def findEnemies():
    return self.findEnemies()
    
def findItems():
    return self.findItems()

processAll(findEnemies, kill)

processAll(findItems, pickUp)

In this case, while the code compiled without any error messages, the hero did not actually do anything and was immediately slaughtered helplessly by the surrounding ogres.


#2

That’s right, passing functions around is not supported in any language yet. See:

suspecting that the root of the problem might be that Python self is directly translated to this when cross-compiling to Javascript

I’ve just tried your sample code in the Aether demo page and it works fine. The compiler maps self to the correct this value, so function definitions work correctly. The problem is only the yielding behavior as I’ve linked above.