Live data from Hacker News

Design Patterns Are Temporary, Language Features Are Forever

ptrtojoel.dev

61–67 of 67 posts

Re: Design Patterns Are Temporary, Language Features Are Forever

#61

Earlier quoted context omitted.

> that software design patterns are sometimes failures of the language when they have no concise way of expressing these kinds of concepts. This is _the_ most common comment you hear in any language design discussion, and it's so boring. Java doesn't have visitors because it's the best the language could come up with. It has visitors because of a particular dogmatic adherence to OOP principles. A fundamentalist readi…

> Java is perfectly capable of expressing an enum I think this is a bit of an exaggeration, unless you're talking about very modern versions of Java (sealed interfaces and better pattern matching). Java has no good way to attach different data types to each enum variant (a la ADTs) except inheritance, and until recently switching over class types was a PITA.

Enums were added in java 5 and I'm pretty sure you could switch on them from day one. From that point you just need a single class (call it TreeNode) that holds a value of that enum (say the node type) and some fields, and you can navigate it and switch over the node type without any sort of visitors.

"But what if I have a leaf node. Wont that have a child pointer, even though it doesn't need it" Sure it will. Who cares. You don't need to make it harder than it has to be. All the new stuff just enables you to get more type safety, it was never necessary.

Re: Design Patterns Are Temporary, Language Features Are Forever

#62
post #9

You don’t come across visitors every day, and they aren’t something to reach for instead of a simple switch, but if you are writing a Webpack or ESLint plugin or something like that, you might encounter them for traversing an AST. It’s not just an OO thing, either. I learned the visitor pattern in pretty ideal circumstances: from a classmate, back in college, when we were writing a compiler together for a class proje…

Someone else beat me to it. Will answer anyway. Had a very similar experience to yours with one important exception. The visitor pattern is relevant for traversing ASTs in single dispatch languages. Most notably, this includes Java and C++. The alternative concept is multiple dispatch and it is way more anti-fragile. This is where the next step in college literally was to learn the concept of cargo-culting. The conce…

The visitor pattern is relevant in multiple dispatch also; just most of its boilerplate goes away, so that only the visitation remains: traverse the AST (or whatever structure) and invoke the given method with the node and visitor as arguments.

For list in Common Lisp, the ancient mapcar function can do this:

  (mapcar (lambda (node) (visit node visitor)) node-list)
We still have to write method specializations the different combinations of node and visitor types we need, for the generic function visit.

  (defmethoc visit ((left if-statement) (right print-visitor))
    ... logic for printing if statement
    )


It's just less fragmented than the single dispatch version, because we don't have to perform two single dispatches to obtain one.

Re: Design Patterns Are Temporary, Language Features Are Forever

#63

Earlier quoted context omitted.

Someone else beat me to it. Will answer anyway. Had a very similar experience to yours with one important exception. The visitor pattern is relevant for traversing ASTs in single dispatch languages. Most notably, this includes Java and C++. The alternative concept is multiple dispatch and it is way more anti-fragile. This is where the next step in college literally was to learn the concept of cargo-culting. The conce…

What do you mean by "multiple dispatch"? What's an example of a multiple dispatch program?

Multiple dispatch means that a method is selected based on the run-time type of more than one argument, rather than just "the object" (leftmost argument).

This is beneficial to the Visitor Pattern, because the pattern needs to traverse a structure with polymorphic nodes, and invoke logic that is based on the type of each node, and on the type of the visiting object.

The familiar single-dispatch Visitor Pattern introduces an emulation of double dispatch via two single dispatches. First a "accept" method is invoked on each Node of the traversed structure, taking the visitor as the argument. This accept method is a stub which calls the "visit" method on the visitor, passing the node as an argument. The static type of the node is known at that point, so the visitor can statically dispatch different overloads for different nodes. I possibly have some of this backwards, but it doesn't matter; it will work with different naming. Under multiple dispatch, we can just call a single generic function visit which is dispatched for the node and visitor in one step. If it is a printing visitor, it prints the node, and so on.

Re: Design Patterns Are Temporary, Language Features Are Forever

#64

Earlier quoted context omitted.

> Java is perfectly capable of expressing an enum I think this is a bit of an exaggeration, unless you're talking about very modern versions of Java (sealed interfaces and better pattern matching). Java has no good way to attach different data types to each enum variant (a la ADTs) except inheritance, and until recently switching over class types was a PITA.

Enums were added in java 5 and I'm pretty sure you could switch on them from day one. From that point you just need a single class (call it TreeNode) that holds a value of that enum (say the node type) and some fields, and you can navigate it and switch over the node type without any sort of visitors. "But what if I have a leaf node. Wont that have a child pointer, even though it doesn't need it" Sure it will. Who ca…

You're getting downvoted but I don't think you're getting the benefit of understanding the disagreements. The benefit of visitor is for when you need multiple different TreeNode classes with different aspects, either different member variables or different methods/implementations themselves. In that case, the unused child ptrs are the smaller of the class modeling difficulties. For example, if you had a single base TreeNode class with the enum, after switching on the enum you need to explicitly downcast to the type. The dual-dispatch approach bakes this into the visit-accept protocol.

The last time I worked on a complex syntax tree structure, I used the approach you suggested because _editing_ a Visitor suite is a pain in the rear. Only terms that had special payload data (numbers, pointers to metadata objects, etc.) need downcasting.

Re: Design Patterns Are Temporary, Language Features Are Forever

#65

I disagree with the main thrust of the article, that the Visitor pattern is primarily a primitive way to do pattern matching. For one, the Visitor pattern (as written in the article) fails to fulfill a core feature of Rust pattern matching, which is having a compact language to describe when something matches based on values, as opposed to the concrete type. For another, you could equally well say that if-else blocks…

Visitors let you do both. That said, I have used visitor a lot and it never was in a context where lambdas would have helped. There wasn't any variability in the code path such that I might have different implementations of a function at different times, and as the Visitor would have some state in it (an accumulator, a set of config variables, etc.) composing those as lambdas and dispatching to them seems like it would have been less convenient.

Re: Design Patterns Are Temporary, Language Features Are Forever

#66

I think the visitor mimics pattern matching, but it really behaves/feels different. I think the visitor is really closer to a bridge from OOP land into FP land. In FP its difficult/impossible to add new types but simple to add new mappings/pipelines for those types. In OOP its easy to add new types but difficult/impossible to add new mappings/pipelines for those types (try transforming a POJO without lombok @Builder…

That's the expression problem right ?

Re: Design Patterns Are Temporary, Language Features Are Forever

#67
post #25
post #20

> because that's a major L What's "L"? Am I getting old?

"Loss" I believe, contrast with "W" for a win

Christ. I find uncontrolled use of three letter acronyms irritating enough. I wasn't banking on one letter acronyms.
Post reply on HN