Hacker News new | past | comments | ask | show | jobs | submit login

Or, use pattern matching for significantly less boilerplate. Double dispatch isn’t free either.



Is this actually double dispatch? Visitor is a pattern that can be used for double dispatch, but I only count one guaranteed dispatch here.

I'm not convinced that folks here saying, "We just us pattern matching like functional programming does" actually know how modern functional programming does this. From the perspective of runtime overhead and code size, this approach is very similar to recursion-schemes.

Where RS excels over this approach is not in the use of pattern matching, but in the fact that it can reuse the functor structure to not even have to write the descending algorithm; it comes for free as part of your fixpoint functor.


Or use type classes.

I do think visitor pattern, type classes and pattern matching have different areas where responsibility lies and how it is distributed (with pattern matching the most local, visitor pattern extensible without by classes and type classes - which I prefer - extensible at the call site).


I think the Visitor pattern is an antipattern. I've never seen a non-trivial application that didn't become a huge mess. It fundamentally violates the basic OO principle of encapsulating state and behavior. Anything else -- reifying the events into first-class types, factoring out the overlap into a new type, generics, even Scala-style traits -- is better.


> the basic OO principle of encapsulating state and behavior

Not everything you might want to program necessarily fits the principles of your religion.

An abstract syntax tree in particular isn't something where information hiding makes a lot of sense. You need the details in the tree.


The whole point is to separate behavior from the datastructure. Yes, this doesn't fit nicely into OO principles, but strictly that's true any time you externally query an object for state and make a conditional decision based on the result.

Inevitably, any method (visitor, pattern matching, if elsif) of customizable walking of a tree datastructure separates behavior from the tree object. That's the point, though, again.

Now, you can say wanting to do that (customizable tree walking) in itself is an antipattern and shouldn't be done. That just doesn't match well with reality.

I've seen many cases where the visitor pattern is about the best one can do. Yes, it becomes ugly but that's usually due to the complexity of the attempted tree walking, e.g. for transformation.

A lot of the alternative approaches in the functional world become ugly too once there's a need to offer maximum customizability, e.g. in terms of order of evaluation.

If you are able to sufficiently constrain the domain you can get away with some simplied templates, but where I see visitors most often is in API's wanting to offer any kind of tree walking.


> It fundamentally violates the basic OO principle of encapsulating state and behaviour.

The kind of principle that most realise is a mistake of enormous proportions.


You're looking at an example use of the Visitor pattern that both simplifies and optimizes code.


We absolutely use a variant of this technique in Haskell. We absolutely do not need type classes (of any order) to make it work (although type classes and type families certainly clean up the implication). We need a Fixpoint lifting, a way to consider an object as a functor (which we could do at the value level). The rest is simple functions.

I was surprised how similar it looks in Java. I hadn't considered how it would look.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: