Live data from Hacker News

Design Patterns Are Temporary, Language Features Are Forever

ptrtojoel.dev

21–30 of 67 posts

Re: Design Patterns Are Temporary, Language Features Are Forever

#21
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 concept of multiple dispatch is considerably more useful than single dispatch.

Many years later the realization hit, that OOP, singletons, DB mocking and monads are the hard parts [1,2]. Then you can even skip multiple dispatch in favor of low latency. C++ wants this but its ecosystem has no idea (as in zero) of how to get there [3,4,5,6] (-Ofast -fno-fast-math). Then the "Patterns" (capital P) melt away.

On a semi-related note, it seems worth pondering whether strict typing requirements and/or a missing garbage collector make macro programming and AST work so hard in non-lisp languages. Think I read somewhere that some people considered Rust macros hard. Sounded like they were harder than they should be, which means that the language designers piled on incidental complexity. Macros are difficult enough as it is. And worth it. Even Python pilfered the "with" syntax.

[1] http://somethingdoneright.net/2015/07/30/when-object-orienta...

[2] https://lobste.rs/s/vbivyq/synchronous_core_asynchronous_she...

[3] https://moyix.blogspot.com/2022/09/someones-been-messing-wit...

[4] https://news.ycombinator.com/item?id=32738206

[5] https://matklad.github.io/2023/11/15/push-ifs-up-and-fors-do... Note, that Fortran and Functional Analysis got this right ages ago. Excuses are now few and far between. All of use are late to the party.

[6] https://news.ycombinator.com/item?id=38282950

Edit: typo

Re: Design Patterns Are Temporary, Language Features Are Forever

#22

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…

You seem to have given this some thought.

Honest question: What is your current estimate of how much the OOP side is impacted differently by Composition vs. Inheritance, especially when contrasted with FP?

Re: Design Patterns Are Temporary, Language Features Are Forever

#23

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…

How do you achieve multiple dynamic dispatch with lambdas? Without pattern matching, don't you need the visitor to incrementally dispatch?

Re: Design Patterns Are Temporary, Language Features Are Forever

#24
If I may nitpick, the call to children’s accept methods should be in the visitor, not the parent. Imagine you’re writing an XMLGeneratorVisiter. The visit method for the parent would print , call child accepts, and then print . If you do it the way it is done here you lose the control on when the children are visited.

Also, the point of the visitor pattern is not just pattern matching/polymorphism. Of course you could do it with polymorphism or conditionals or whatever. But the visitor pattern reduces coupling and increases cohesion. So you get a more maintainable, testable code base. Pattern matching with a candied switch doesn’t give you that.

Re: Design Patterns Are Temporary, Language Features Are Forever

#26
post #5

Earlier quoted context omitted.

Order and elegance? Some people say that GoF patterns are just a way to cover up for OOP-centric language shortcomings.

Object-oriented order and elegance compared to an object-infested mess of special cases and complications. Remember that 25 years ago C++ wasn't a pleasant place and Design Patterns was an impressive step forward.

Oh, I do remember the grim story really well. I was there. I still have all the books. And the scars.

Back then I was a young innocent programming soul trying to reconcile C++ and GoF and UML and all that. And Modern C++ Design. And const here const there const copy constructor by reference.

Anyway. I like vanilla C. And Go at times.

Re: Design Patterns Are Temporary, Language Features Are Forever

#28

I haven't looked at patterns since the GOF days, so maybe they grew closer to Alexander's as they matured, but the original ones were very much ways to speak about things so they'd be politically palatable in an everything-is-an-object world. You just wanted some data? "Flyweight". You just wanted some functions? "Strategy". etc.

It amused me that Alexander's _A Pattern Language_ was 90% about habitability and 10% about building whereas I had the feeling GoF was the opposite. That is, I believe Alexander's version of design patterns would have things like "Intention Revealing Names" and code reviews focusing on "Clarity, Consistency, and Correctness (in that order)"--things that help subsequent developors live in and enjoy the code and design…

Software exposes (at least) two faces ... the user facing one ("habitability") and the (future) developer facing one ("building").

GoF approaches from the "building" side since it was created by and for programmers. Another way of thinking about this is that GoF is describing the experience of the design as a developer having to "inhabit" it, rather than a user's experience of the same.

That's why Alexander is not a particularly useful book for builders, since it focuses on the user's experience of the design when inhabiting it, rather than the constructors' experience of the same design when creating or modifying it.

A version of GoF that focused on the user experience would be a completely different book than the one we know.

Re: Design Patterns Are Temporary, Language Features Are Forever

#29

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…

You seem to have given this some thought. Honest question: What is your current estimate of how much the OOP side is impacted differently by Composition vs. Inheritance, especially when contrasted with FP?

Honestly, for all the OOP talk about composition its rarely done well and afaik no major OOP language supports that paradigm, so it's a bit tough to say, as a really good take on it from a language level could affect my opinion a bit. Java 21 seems promising in this regard with switch + record, but the legacy java layer seems to drag it down.

Currently I'm not entirely convinced composition is a silver bullet that will save OOP and from what I've seen it is also somewhat antithetical to OOP - you are constructing a bunch of "has-a" relationships and expecting it to relate to behaviour (generally done by inheritance / "is-a"). So in "saving" OOP composition will likely kill it.

Instead I think we'll see more (especially newer) languages move towards FP by introducing composition (like rust / golang interfaces). I think it's because composition maps quite well to the FP concept of a composite data type (like a struct / tuple) as well as function composition. But at the same time I think we'll see a lot of in-between languages (again rust / golang) where we take some stuff from procedural+oop and mix it with a bit of functional programming (especially in data pipelining areas). Similar (but opposite) to how Java 8 introduced the streams monad.

Re: Design Patterns Are Temporary, Language Features Are Forever

#30
post #14

I've seen it said that Alexander working on this stuff just at the moment of peak OOP-timism is a great shame/tragedy. I'm inclined to agree. Functional purists like to glibly say that their patterns are discovered rather than invented. I used to Pooh Pooh this a bit. Then I had to write a class just to have a function to call. They're right.

> Functional purists like to glibly say that their patterns are discovered rather than invented.

As someone who suffered through the whole OOP-madness I found this presentation so refreshing: https://fsharpforfunandprofit.com/fppatterns/

Post reply on HN