Hacker News new | ask | show | jobs
by chubot 280 days ago
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

1 comments

yeah, pytype used a mix of visitors and if statements (we were trying to retain 3.8 compatibility for a while so we didn't switch to `match`), depending on what fit various parts of the code best. it wasn't a particularly dogmatic "we will use visitors because that's the one true design pattern" thing, just that some problems fit the pattern neatly.