Hacker News new | ask | show | jobs
by gugagore 2228 days ago
"no abstract frills attached" I can't tell what you think a frill is, but I can't square that statement with the rest of your post, and with the OP. Higher-level constructs might require language features like template metaprogramming, or a level of indirection. There are a few ways in which you can have "the same sort of code".
2 comments

A 'frill' in this case is any construct that is not obvious to a person a who has programmed a few years in the particular language. For example, this definitions makes most C++ templates used outside of STL-like usage very frillic.

"Higher-level constructs might require language features like template metaprogramming, or a level of indirection."

I think we have different definition what a "higher level" means. To me it means a particular pattern has been identified in the code and lifted to an implementation that needs less thinking and fewern lines of code.

You can have quite high level clever program logic using the basic algorithmic toolbox - the basic containers and large zoo of well known algorithms to operate on them - the array, the list, the map and the graph.

> To me it means a particular pattern has been identified in the code and lifted to an implementation that needs less thinking and fewer lines of code.

To give you a sense of how I think about this, we can just focus on control flow. One option for control flow is very uniform and easy to grasp for anyone, including a programmer from 1950: there are [conditional] gotos and labels. Another option is if/else, while, for, try/catch, yield, return f(),...

So what gives? Particular patterns of gotos/labels were identified and lifted into a situation that needs fewer lines of code. Does it need less thinking? That's where it gets tricky. It's obvious to me that the programmer in the 1950s will look at try/catch and require much more thinking than if they just had goto/label code in front of them.

Template metaprogramming (I don't understand what usage is distinct from STL-like usage) is exactly about identifying a particular pattern and literally lifting a concrete type into a type parameter so that now you have a related family of code. Analyzing the code requires higher level and lifted thinking, the same way that manipulating algebraic expressions instead of concrete numbers does.

That's what I mean by higher level.

I agree that code should strive to reuse "fundamental" container types (implementation, or at least interface), but I don't see the connection to the current conversation, aside from the feeling that using those containers without lifting the types (whether in your mind, or in the language) is impossible.

> Template metaprogramming (I don't understand what usage is distinct from STL-like usage) is exactly about identifying a particular pattern and literally lifting a concrete type into a type parameter so that now you have a related family of code.

I believe GP was referring to the myriad techniques for using templates not as containers, but as type-level functions, and composing compile-time programs that rely on SFINAE, variadic templates, andffunction overloading rules to express functional programs in the C++ template language. You can find examples in boost in various areas.

One somewhat spectacular example is boost::spirit/boost::qi, which allow you to define parsers with a DSL directly in C++ (e.g. using `*c` as '`c` 0 or more times').

If you're doing foo a lot, you make a foo() function. That doesn't mean you have to create a pure virtual FoolikeOperation class and FoolikeOperationFactory, a concrete ActualFooFactory and an ActualFooOperation class.
Suppose you do foo a lot. And sometimes you need to do either foo or bar inside of baz.

You can pass a flag to baz, to choose either foo or bar. Now you have a closed set of possibilities. If you want to extend the functionality e.g with a plug-in, or got any other reason you want to avoid committing to the choice, then you either need

1. first class functions, so that you can pass in foo or bar or whatever.

or if you don't have first-class functions, then you need a

2. FooLikeFactory to make a FooLike object based on a runtime value (e.g. read from a configuration file), and then you can call your FooLike object from baz.

I like the quote that design patterns are bug reports against a language. The factory stuff you're talking about doesn't just exist for fun. It solves an actual problem. I hate Java as much as you do, I'm sure, but I value understanding the reason the patterns exist before I decide to just use a language where I don't need to do any of that stuff.

Oh, for sure, you can still find yourself in a situation where that kind of heavyweight design pattern is appropriate. And if you do, then by all means uses it. I think they're just saying don't jump straight to the top of the tower of abstraction when the first step or two up the staircase will do what you want.
Yes, this very much :)