The PLT position on this is that loops are too expressive. We'd like to use the least powerful tool that can do the job. Loops can express all sorts of incorrect versions of the intended algorithm. It's preferable to try to identify the reusable structure in the algorithm (it might be a "scan" or a "fold", for example) and implement that once and for all. We then provide a simple interface to that algorithm, without any footguns.
> That's like saying a bag is too expressive because I can put all kinds of things into them.
That's entirely accurate. A bag is "too expressive", in that sense. Sometimes you want to constrain the kind of container so you don't put the wrong kind of thing in there.
Another analogy: types. "Any" will let you use anything, but sometimes you want to say "only allow Integers here".
What I intended to hint at is that a bag being expressive is not the issue. Yeah you sometimes want to label the bags, or make special purpose bags. But bags as they are are not too expressive. Them being expressive allows for all that other stuff. Their core utility is what we're after and the rest is secondary support and should be treated as such or else we get lost.
If we act like we're not actually dealing with bags at a fundamental level, we might mislead ourselves and spread the belief that the rules and labels around the bags are what matters. No, they help you (temporarily) to use the bags in a specific way in some context.
In fact, computers are extremely expressive, (bag like) things. The constraints are auxiliary. I think it's important that we keep reminding us what programming is and that it serves a direct purpose, while the bureaucracy is a support structure at best.
Constraints enable reasoning, both automatic and manual.
Loops fit the single-core CPU hardware paradigm extraordinarily well. As soon as you start targeting modern hardware, more constrained recursion/iteration schemes start to buy a lot more in terms of both developer time and compiler complexity.
Agreed that computers are extremely expressive. I think the constraints are necessary though, and not just bureaucracy. After all, what are bugs (especially harmful bugs) but a failure to constrain choices?
More practically, a List is too expressive, if all you need is a Set - which is true and generally good advice to use Set instead of List, if possible.
From what kind of programming hellhole do you come from, where using Set instead of List is good advice? Lists are very natural constructs for computers, sets aren't.
Sets specify a particular interface but not a particular implementation or backing data structure. You can substitute different implementations (including ones backed by lists, vectors, hash tables, and others) depending on your particular needs.