| That's not the only difference - the other issue is that you lose the stack, and must rely on member variables instead. If you search for pop(), you can see that self.expected_ret.append(ret)
self.generic_visit(n)
self.expected_ret.pop()
and self.push(narrows_true); [self.visit(s) for s in n.body]; self.pop()
self.push(narrows_false); [self.visit(s) for s in n.orelse]; self.pop()
In the functional style, you just pass a param using the stack, rather than using an explicit stack.It's not so bad here, but with a big enough language, and more complicated algorithms, the mutable member variables basically become "mutable globals". And if you re-call visit() at arbitrary depths, IMO the algorithm gets obscured. --- That said, I agreed here that visitors are useful when you need to say traverse all string literals in an AST, at arbitrary depths: https://lobste.rs/s/jdgjjt/visitor_pattern_considered_pointl... --- A sign that this issue isn't settled is that two of the more complex type checkers make opposite decisions - MyPy uses visitors extensively - https://github.com/python/mypy/tree/master/mypy - TypeScript mostly uses switch/case functions - https://github.com/microsoft/TypeScript/blob/main/src/compil... I'd be interested in analysis of why that is, but I suspect it's mainly style |