News for hackers. Stuff that matters.
Re:Anti-Patterns by ncmncm on Sunday June 02, 2019 @04:49PM (#20078071)
This article, like most, rides on the idea that Patterns are Good. But each pattern really represents a failure in our languages and language ecosystems. An anti-pattern is just a bigger failure.

We have a different name for the true successes: Libraries. When we can encapsulate a solution to a recurring problem, and make a clean interface to it that does not dictate the architecture of the whole system that uses it, we put it in a library, document it, and maybe publish or even standardize it.

The merit of different languages for constructing systems (as opposed to myriad other uses for languages!) turns on how effectively you can build, deploy, and use libraries in those languages. Each place where no library can be constructed or used, requiring deployment of a pattern instead, represents a failure of the language design or ecosystem to enable encapsulating and generalizing the idea. In a Better Language, we would use a core language feature or library, and not need to code the pattern over, yet again.

When we propose extending a language with a new feature, our best arguments for the feature arise from examples of libraries we could write, that we cannot, now. Or, more frequently, are of how it would enable better encapsulation and generality for the kinds of library we already use. (Previously impossible libraries are usually conceived later.)

This is the reason that C++ still dominates in system implementation, despite that its most devoted users are its worst critics. It originated the goal of the zero-cost abstraction, has carried it farther, and is still moving.

As an example, the hash table is a common Pattern in C. C coders are always writing custom hash tables and hash schemes, because you too often can't get tolerable performance from a library version. In slow languages, the performance overhead is considered negligible, and the built-in hash table dominates. Meanwhile, in C++, it would be foolish to code a single-use hash table. The std-library one is fast and forgiving; and better ones, deeply analyzed and optimized with detailed tradeoffs (entry stability, modify vs lookup speed, etc.) and thoroughly tested, are easily found and dropped in.

Sometimes a library can't displace a pattern, and you need a core language feature. C++ has templates. Rust has its borrow checker. C++ and Rust are getting "await". In languages with the right bent, these core features combine and breed to provide encapsulation for ever more powerful libraries.

Powerful libraries are not just a convenience, saving coding time. They add correctness, at scales large and small, not available from patterns. They amortize and capture optimization effort far beyond what would be affordable for single-use code.

Obligate garbage-collection is poison to a powerful-library ecosystem, because the effects of tradeoffs needed to meet performance requirements reach deep into the shared semantics libraries rely on. A powerful library for an obligate-GC language would need to accommodate all the different ways GC might work. In practice, nobody has time for that, so library dependencies in such languages instead constrain the tradeoffs, and many libraries are likely not to be usable in a system that must make them. With fewer uses to amortize over, libraries get less attention, and are fewer.

C++ shows its age, but nothing to replace as a powerful system language is above the horizon. Rust might get there, eventually, if its minders raised their sights, and if development of C++ were to slacken.

Most coding, meanwhile, is done on smaller systems, in more forgiving environments, where abstraction overhead is tolerated. There is little pressure to enable replacing patterns with libraries. Patterns are still in the vocabulary there.

There are no comments on this comment yet.