I've never really understood the Ruby community's attitude toward for loops. I learned Ruby as my first language and read many blog posts and instructional books that told me to absolutely avoid the for loop. Of course when I started to learn JavaScript and C, I had to figure out their versions of the for loop then, and it made me start wondering why there had been such opposition to something that seemed to be a normal part of the Ruby language. I can understand "idioms" if they have some benefit over non-idiomatic versions, but in a language like Ruby that supposedly embraces TMTOWDI, I can't, for the life of me, figure out why .each is always best.
I don't think using a for loop is "taboo" among Rubyists in general, just for iterating over each element of an array, where Array#each, Array#collect, and Array#inject are preferred. This probably comes from the influence of Lisp and its emphasis on writing code as a series of list operations.
To my mind, anyway, using each/collect/inject expresses intent much more clearly than a for loop. If a clearer approach is available, why not take advantage of it?
I, too, think like that, although Ruby's nomenclature frequently confuses me. Coming from Scheme/Haskell I'm quite at home with 'map', 'filter', and 'fold'.
However, Ruby uses the methods you mention, "collect" and "inject", and these in turn have a few synonyms. And as best I can tell, Ruby's 'filter' variant, 'find' collides with ActiveRecord. What's the general community take on these functions? Which name is commonly used, and how do you do filter in Rails?
> I, too, think like that, although Ruby's nomenclature frequently confuses me.
Most of them come from Smalltalk's Iterable protocol[0]: that's the source for `select:aBlock`, `collect:aBlock`, `inject:thisValue into:binaryBlock` (Smalltalk uses `fold` when there's no starting value, and `inject` as "fold by injecting initial value"), `detect:aBlock` and `reject:aBlock`.
Smalltalk also uses `do:aBlock` where Ruby uses `each`, likely due to `do` being a keyword in Ruby.
Also, `find` is not `filter` (that's `select`, aliased to `find_all`). `find` is also `find` in Haskell[1] (and maps to Smalltalk's `detect`, also useable in Ruby).
> 'find' collides with ActiveRecord
Uh... no, ActiveRecord collides with Enumerable, I'm pretty damn sure Enumerable came first.
> how do you do filter in Rails?
What's wrong with #find? Or #where? Or #find_by_*? Same name, different namespace, different meaning. Kind-of the point.
Programming isn't just about giving instructions to a computer, it's an act of communication to anyone who will read your code down the road. Having a consistent set of rules is an important part of that communication. Just as a style guide for a natural language can help readability, good conventions can make code more readable. Python goes as far as defining an official style guide (PEP-8)
I always interpret "idiomatic" as "avoiding performance issues". In Python, for example, using the join method on strings is not only idiomatic, it's performant. Even if a particular idiom has no effect on performance, the worst that happens is I write idiomatic code. Not only that, but idiomatic coding allows me to write performant code without having to understand why it performs well. I don't know Ruby, so I can't comment on each vs for loops, but in general there's a practical, performance-based advantage to idiomatic coding.
Not always though. I don't know if this is still the case, but "while true" used to be more idiomatic in Python than "while 1" even though the latter had better performance due to the state of the cpython implementation at the time.
It may be the case that at any given point, the idiomatic way is not the fastest. However, if idioms are widely adopted, the language implementers have good reason to optimize them. I'm not saying that's what happened in this case, but I think it's reasonable claim to make in general.
> I always interpret "idiomatic" as "avoiding performance issues".
Huh? That is definitely not what it means. That may be a byproduct if the language implementers then make the social mores they admire the ones that perform the best, but otherwise that's not what makes something an idiom or a social more.
> That may be a byproduct if the language implementers then make the social mores they admire the ones that perform the best
I understand the definition of the word idiom. I'm saying that the quoted scenario is, in fact, not just hypothetical, but likely. Thus, following idiomatic style can help one avoid performance issues.
Not at all likely, and in fact if you believe this without first investigating its validity then you may be bit by bad performance. A very real scenario is that you use something blindly because everyone else does, thinking it performs well, and then you find out it actually doesn't.
The word "idiom" has two different senses. First, there's the sense that the author is discussing. In this sense idioms are expressions whose meanings aren't derivable from the meanings of their parts (linguists call this "non-compositionality"). The other sense of "idiom" simply means "an expression that characterizes idiomatic speech.
Now "idiomatic" also has two senses. First, it can mean "having to do with idioms". Second, it can mean "peculiar to a particular group, individual or style". (See http://www.merriam-webster.com/dictionary/idiomatic)
So, I think when people speak of idioms regarding programming languages they're using the second of the above senses. While this sense might be characterized as having to do with social mores, I don't think it's a misuse of the word "idiom". People don't mean to say that .each statements are non-compositional in the way that "kick the bucket" is. Indeed, given that programming languages have formal grammars/semantics it's hard to imagine what non-compositionality would be at all (though I'm sure any good Perl programmer could probably give some examples!)
If you want to be clear in your writing you avoid idiomatic speech that will be unfamiliar to your audience. Using the idioms of your audience doesn't impede clarity. The woman in _Airplane_ who "speaks jive" employs idioms to increase clarity!
Idioms, by definition, aren't universal. (By etymology, too: an idiom is idio-, one's own; think idiosyncracy or idiolect.) it. It's very odd to contrast the idiomatic and social mores.
The linguistic analogy is really confused, anyway:
"These idioms are also not language dependent, but actually locality and culturally dependent. I could move to England, the home of English, and they'd use many new and different idioms.
What you don't see is people in England demanding that I say "the dog's bollocks" in order to visit."
1. There is no single language "English" which has its home in England but is also spoken in America, Australia, Canada, South Africa, etc. The contrast between language and locality/culture is extremely tendentious.
2. You had better believe that certain changes of locality and culture are accompanied by demands that one change one's idioms. If I go for a job interview at a conservative law firm, I am not going to praise something by calling it "the shit". If I normally spoke AAVE, I would do my best to suppress that.
3. American English and British English are mutually intelligible (but there are chains of mutually intelligible Englishes whose extremities are not mutually intelligible), so you can speak AmEng in Britain. If you want to speak the way your hosts speak, though, you'll say "boot", "lift", etc. when you would otherwise have said "trunk", "elevator", etc., and you might find that some of your American idioms actually aren't comprehensible. Your British hosts might well demand that you say something they understand to them.
4. You can speak AmEng in Britain, and you can write Fortran in Ruby. It is pretentious for an American to affect an accent while in, or having come from, Britain. By contrast, it is only reasonable to do things Rubyishly in Ruby.
"Because people quite literally freak out when they see non-idiomatic code, and go to great lengths to correct everyone who doesn't write idiomatically, these can't be idioms."
So ... what do you think gets taught in elementary, middle, and high school english classes? Idiomatic formal english! You are corrected if you don't write idiomatically! Many people freak out when they see nonstandard forms of English!
I think the use of 'idiomatic' that daviddaviddavid had in mind is this one[1]:
1. a. Peculiar to or characteristic of a given language.
b. Characterized by proficient use of idiomatic expressions: a foreigner who speaks idiomatic English.
That use of the word 'idiomatic' is very common, and although it's related to the word idiom, it's not quite the same thing. An idiom, as you say, is a phrase that you can't guess the meaning of just by glossing each of the individual words (a favorite example - in Puerto Rico, though not all Spanish-speaking countries, a flatterer is a 'lambeojo', literally 'eye-licker'). But someone who speaks Spanish idiomatically or who writes idiomatic French does so 'like a native'. It's a good thing. So when someone says that 'each' is 'idiomatic Ruby', that's probably what they have in mind.
All of that said, I can understand wanting to teach beginners the for loop first. But I don't think a Ruby course should finish without looking at each. If a person plans to read any real Ruby, they had better be ready for lots of iteration with each.
Why does the author insist that to teach each to a beginner he has to teach all of those concepts? Sure, to understand it fully you need to know about those things, but you can definitely get a beginner far enough along without explaining every detail.
Did K&R explain everything about the preprocessor with their "Hello, world!" example? Or the implications of different return codes from main(), what 'return' from a function even means, etc?
> Why does the author insist that to teach each to a beginner he has to teach all of those concepts?
Because you aren't teaching, and it merely becomes rote memorization. After all, what does || really mean? What does it do there? Without explaining it, it's magic. And instead of learning, the student must disassociate || with what it really and merely associate it with each.
On top of this, you'll have those wondering what || is, and bothered that they are using something without understanding it's importance.
> Did K&R explain everything about the preprocessor with their "Hello, world!"
No, but they explained what that line (#include <stdio.h>) did. They didn't just gloss over it. They covered every line, and every element, including the different braces.
So, either you teach what || is, or you ignore it, and that will only make things more difficult later on.
K&R eventually did, even if they didn't at the very beginning. I also don't teach everything right away. But, if I'm going to teach the concept of looping, I'm going to teach the one that's easiest to grasp and fully know. That's a for-loop, not a .each method dispatch.
The concept of a jump is not one you want to ever teach, and I think you've chosen to go into more detail in one list than the other. In terms of "what does it do", both bits of code call "puts elem" on each element of the array. In terms of "what it's actually doing", the .each example is forming a block and passing it to a method, while the for example is a special syntax with its own scope implications. So the complicated parts of the .each version (blocks and method calls) are general concepts used throughout the language, that you would always want to teach to learners sooner or later. Whereas the complicated parts of the for example - the scoping and the for syntax itself - are dead ends that don't help you learn the rest of the language at all.
>The concept of a jump is not one you want to ever teach,
That is again another arbitrary social more invented by a rant written by Dijkstra. Learning that a computer processes code by using jumps is an important concept to learn, and it's actually a useful technique in many languages. Saying someone should never learn them is just stupid.
Oh, oops. I was overly skeptical nearly to the end because I thought he meant a numeric for loop instead of a for-each loop. I misunderstood the entire distinction, because while there is little reason to pick .each over for-each, there are very good reasons to use some kind of 'each' method.
I don't know where on earth he got "By definition an idiom is something you remove from good clean writing," which is obviously not true (edit: and itself contains an idiom, "good clean", which you can recognize as an idiom simply by reversing the two words), but I think he's right about the important thing, programming language mores. It's crazy odd how what appear as purely technical constructs become nuclei for all kinds of tribal and emotional behavior.
Here's my explanation: the human brain is an identity machine. Apply it intensely to anything over time and you can't help but identify with what you're doing and how. As soon as identity is involved the complete human package kicks in, including emotion and tribalism (banding together with those of like identity in opposition to those of unlike identity). Opposite ways of doing things begin to seem like threats, criticism evokes defensive feelings and so on. If you think you don't function this way, try paying closer attention.
Yes, you avoid idioms in writing if you want it to be clear. If you're going for style, as in fiction writing or for artistic purposes, then do whatever you want.
I'd like to see an example of a good writer, or even one sufficiently long piece of clear writing, that doesn't use idioms. Language is saturated with them.
You'd be on more solid ground (and closer to your point about loops) to say that, when teaching foreign languages to beginners, idioms are best avoided because the student is struggling just to know the individual words. Even then, though, I doubt I ever took an introductory language class that didn't teach at least some idioms; you can't get a feel for a language (or fully understand any real-world text) without them.
>I don't know where on earth he got "By definition an idiom is something you remove from good clean writing," which is obviously not true
Maybe from all those classic books on writing, like the "Chicago Manual of Style", "On Writing Well" and "The Elements of Style", which all agree on the point.
Where you got this bizarro impression that idioms are NOT to be avoided in writing? Idioms are cliches, and they needlessly obfuscate a text.
I suppose it's foolish to belabor the point, but (a) is it just me or are you sounding a bit of a bully? and (b) everything you wrote is untrue.
My impression comes from observing language: it is saturated with idioms. You can't throw them all out (without a lot of unnatural effort) nor is there any need to. You might as well say that a musician should use only notes and not chords, or avoid standard chord progressions. If you can find any significant piece of writing that avoids idioms, I'd like to see it.
Idioms are not cliches. An idiom is a phrase whose meaning is more than the sum of its words. A cliche is a phrase that has become hackneyed through overuse. (Nor, by the way, are cliches necessarily obfuscatory. "Get your ducks in a row" is, but "Live and learn" is not.)
Style manuals have their place but are hardly scripture, and there are countless examples of great writers breaking every rule in the book. Indeed, Strunk & White breaks its own rules, sometimes when describing the very rule it's breaking (which is part of its charm [1]). So even if your claim were correct, it wouldn't prove anything. But I'm pretty sure it isn't correct. Since you claim that Chicago, Zinsser, and Strunk & White all agree on the point, please show us where; I'd like to see. All three of those texts are searchable online and I couldn't come up with anything. But I only tried for a few minutes.
[1] Just for fun, here is an example: "Students of the language will argue that try and has won through and become idiom. Indeed it has, and it is relaxed and acceptable. But try to is precise, and when you are writing formal prose, try and write try to." How can anyone not love E.B. White?
This is probably completely apparent to anyone who's had to learn an ancient language (4 years Jesuit high school Latin can I get a qui qui?!) --- to understand ancient Latin you need to learn the idiom, not because the Romans were overly fond of cliche, but because they were speaking in a different historical context in which their audience could be expected to understand that "nut" was synonymous with "toy", or Greeks could be expected not to track dates on calendars.
So just as reading the simply Yacc grammar for MRI Ruby is not a particularly great plan for mastering Ruby, learning the rules of grammar and memorizing individual vocabulary words isn't going to give you convincing conversational mastery of a spoken language.
>Style manuals have their place but are hardly scripture, and there are countless examples of great writers breaking every rule in the book. Indeed, Strunk & White breaks its own rules, sometimes when describing the very rule it's breaking (which is part of its charm [1]). So even if your claim were correct, it wouldn't prove anything.
Breaking a rule ocassionally is not the same as not having the rule on the first place. For one, they can "break their own rule" precisely because the rule exists. They break the rules they set with caution and only when the feel it is needed. That's the way it is with most rules, about writing or anything else. The rule provide a guideline for the 90% of times.
(Edited to be less irritable.) You haven't replied to the main point, which is to give examples of your alleged rule from the three style guides you cited. As far as I can tell, it's not in any of them.
I don't see the relevance of the style guide mentioned for the debate over how to teach beginners. When you check out a guide, it has to be assumed you are familiar with pretty much most of the syntax of your language.
Oh, no concern at all about the ruby style guide. I even point people at it in the book so they can start grasping and writing code with other people. My mention of the guide is not intended as a knock on the guide at all.
this is a remarkable example of the difference between a coder and programmer - a coder is unable to grasp the insignificance and meaninglessness of a subtle difference between two very similar concepts, while programmer can instantly see that there is nothing to be seen.)
not following the standard idiom of a particular programming language causes people to balk because it shows how unfamiliar the author is and how little code the author has read or been exposed to in that language. Its a huge sign that even though the author may be smart there probably beginner level bugs in the code.
Ruby for-loops have unusual scoping of loop variables, and if you're not familiar with this it can prove to be a source of bugs. I was bitten by this some years ago when I was first learning Ruby, and it took me a while to track down the problem.
An "each" block has the scoping you'd expect, and is more consistent with the rest of the Ruby looping constructs (like select/filter or collect/map). It's not a huge deal, but there definitely are technical reasons not to use it.
for-loops and .each had weird scoping rules until Ruby 1.9. In Ruby 1.9 for some weird reason they fixed .each but not for-loops. No idea why. So, if you're saying use .each for technical solution to a problem in Ruby, then your proposed solution only works in some versions of Ruby.
The pedantic answer is the code block following the for is not parsed as or represented as a code block internally. You don't need the "do" but Ruby slurps it up to play nice. Only block semantics were fixed, but those for constructs like while, until, for, or loop remain the same as they do not introduce new scope.
The book is actually done and being revised, so the fact that you didn't know that even though it's in the first sentence says a lot about your reading comprehension skills.
The idea behind "The Hard Way" is that it's hard because you have to do all the legwork the book prescribes in order to get much out of it. It really has nothing to do with being hard because the concepts it teaches are difficult to grok.
There is an important reason why one would use #each instead of a for loop: encapsulation.
Looping over a collection object requires some knowledge of its internal state (length in the case of a simple linear structure like Array). In most cases where we use for loops, that information isn't really relevant. There is no need to expose it to the outside world and break encapsulation.
Being consistent in using #each helps when you have complex/custom collection objects where iteration can't be done through a simple for loop. The object might not want to expose its underlying collection and hence can't provide a suitable way to use a for loop on it. Or maybe the collection object has dead elements that it wants to skip and so on. There are any number of reasons to hide the implementation details of the iteration from the external world.
Given this and since Ruby has a powerful block syntax, favouring #each fanatically over for loops, IMHO, is a good thing.
"Looping over a collection object requires some knowledge of its internal state (length in the case of a simple linear structure like Array). In most cases where we use for loops, that information isn't really relevant. There is no need to expose it to the outside world and break encapsulation."
The examples from the article don't make me think I need length or any other internal knowledge to use the for..in loop as opposed to each.
My bad, sorry. The 'for..in' construct does not require you to expose the length of the structure.
However, the other argument still holds true: In case of a user-defined collection object, 'for..in' will not work since the underlying collection will be hidden.
Under the hood, 'for..in' just calls #each. Therefore, it is easy to make 'for..in' work with a custom collection: just define #each. And that is what you would do anyway if you were defining an Enumerable custom collection.
Before I learned Ruby, I knew C, Obj-C, C++, Java...all languages that have and use "for" extensively. Coming to Ruby and learning "each" was an eye opening experience for me. Suddenly, the whole notion of iterators become clear to me. (While I had used them in the past, I had only marginally understood them.) After using "each" for a while, I came to realize that I was programming in a functional style without even knowing it.
Earlier today I read through Rich Hickey's posts explaining reducers and actually used them to get crazy performance gains from some Clojure code I was writing...but I highly doubt I would've gotten there without Ruby's "each".
I've seen Zed argue on this point before, and I've always been dubious of his "concern". The one point he makes here, though, that makes me side with him is that "for" is easier to teach than "each". Yes. A hundred times: yes!
The point I will disagree with him on is that "for" and "each" are interchangeable. Semantically, yes. Performance-wise, probably. But stylistically, "each" is a gateway drug to functional programming, and that should not be taken for granted.
(Edit: Where this all breaks down, and where I think Zed is experiencing frustration, is that while some people might have had a good reason for using "each", over time it became a social more. Now people teach and even enforce the use of "each" without being able to explain why. That doesn't mean one should avoid teaching "use each, not for", but it does mean that one should go and find out why.)
Start with "for". Teach "each".
...then go learn Clojure because hot DAMN reducers are going to revolutionize the way we program (but that's another topic for another day).
Well remember, I'm not against .each at all. I'm against it as a first looping construct for beginners. I even start people off in my book by sneaking in functional programming, again because it's easier to teach. They even write a game that is basically one giant sequence of mostly tail calls without knowing it.
Right, I think where people have to get over themselves is that teaching something is often very different from using something. When I was being trained as a chemist, I was started with techniques that were over 150 years old, and that no one in their right mind would use in a professional lab (you really think chemists do tedious titrations when you can buy a pH meter that's 10x more accurate?).
In other words: programmers don't understand pedagogy. Nothing really new there.
I've very much enjoyed the books though...went back and did "Learn C the Hard Way" even though I've been using C for almost 18 years. Can't wait to read "Learn Clojure the Hard Way"... ;-)
I think the reason why for-loops are rejected in Ruby is because of it's Smalltalk heritage.
In smalltalk there are no loops and no ifs... just methods that are executed on a condition. So 'each:' isn't any more complicated than a 'whileTrue:'.
Just take a look at this Smalltalk examples[1]:
-----
[ condition ] whileFalse: [ statements ]
[ condition ] ifTrue: [ statements ]
Outside of the last point about the each method not being a good first exposure to looping, the article was mainly just debating the definition of idiom. That's irrelevant because definitions of English words are overloaded in different fields such as CS all the time.
Nevertheless, this use of idiom does seem consistent with its normal usage. In the context of natural languages, an idiom can mean a phrase of arbitrary origin that has come to have a specific meaning in specific dialects (this is referred to as an idiomatic expression), but the adjective idiomatic can also be used in the sense of "what sounds most conventional to a native speaker" [1]. Likewise, in programming languages, I think of something as being "idiomatic" if it follows either formal conventions [2] or is a commonly used construct.
As for the author's negative opinion of having idioms in a language, I'd imagine most programmers advocate conventions in order to keep code somewhat consistent across programmers. If you didn't have them at all and if every programmer used different constructs to do the same thing, programmers wouldn't be able to use pattern recognition to read others' code and all code written by multiple people would be even harder to decipher than poorly written Perl since there would be infinitely many ways to do it. TWBIMWTDI? :)
[1] I don't want to say what sounds "right" (hence my use of "conventional") since that would necessitate a lengthy discussion about grammatical prescriptivism, but just note that colloquial expressions like "the people who I gave the ball to" can be considered just as idiomatic (under this definition) as formal expressions like "the persons to whom I gave the ball", even if prescriptivists would define only the latter as "correct".
[2] Unlike natural languages whose syntax is naturally occurring, prescriptivism in programming languages makes sense since they're invented by humans to make writers, readers, and/or revisers of code more productive.
Zed is making a number of points, so I don't want to sound like I'm arguing against all of them. But particularly on the matter of each... if all we were talking about were each I think Zed would have an excellent point. But wrapped up with each are all of the other fantastic enumerable methods like map/collect, select/find, inject/reduce, as well as each_cons, each.with_index, map.with_index, etc. These are where the power and expressiveness of ruby really come into play. For example:
With the for each construct you'd have to pass in an accumulator variable and keep track of whether to sum or not. While you certainly can do it in a for each construct, I'd argue that you'd be missing out on what makes ruby, ruby. And getting beginners in that more functional(ish) frame of mind sooner rather than later is a very good thing.
You are right, and once again I am not against using functional programming, OOP, message passing, or any of the things I mention about .each.
I'm against using .each as a first looping construct. In fact, go look at your supposedly better last line of code and tell me if you think a newbie would even begin to comprehend that? Hell I'm a programming veteran and Ruby veteran and I want to metaphorically punch you in the gonads for that line of code.
This is a good point. To play a little off your blog post, a person new to Ruby could view the second line of code more as an idiomatic expression (which it's not really, but it can have the appearance of being one) in that it doesn't make obvious logical sense and is harder to translate to a more familiar language...giving a "raising ravens" (Spanish) vs. "can of worms" (English) scenario.
I think it'd be kinda cool if one could develop sort of a "ruby-normal-form" that could take some ruby expressions and translate them into a more normalized form using things like for-loops, etc....granted normalizing a lot of ruby code might be hard, intractable, or maybe even impossible.
If it threw in explicit returns at the end of each method and added back in all the optional parentheses, you'd be close to the average "Ruby code written by people who don't know Ruby that well" codebases you see in the wild so often.
To clarify, I don't think my original post implied that you were against teaching people how to learn each. Nor do I want to start out teaching beginning rubyists everything all at once. It was more to point out how important the mindset of each is. That's the mindset that you want to reach. And I'm not sure that teaching a construct that you'll never end up using is helpful. I think it just creates a mental construct that you'll have to overcome at a later stage.
I don't think .each is so much harder to learn that it justifies getting a beginner in the wrong mindset. Though to be fair I've only ever explained it to people who've already known some programming, so there is a possibility that I'm underestimating the difficulty of teaching it.
In any event, I thought the essay was totally worth the read even if I didn't agree with all of it. Thank you for it.
Now back to the blog post and see how many constructs to understand .each correctly vs "just accept it for now that this is how it should work, we'll come back later".
Have you ever read such books? the ones with "we'll come back to it later".
>I'm not sure that teaching a construct that you'll never end up using is helpful.
But that was precisely Zed's point! You will certainly end up using it, though you may never use it in Ruby. .each is not transferable, and for-loops are. Zed's teaching Ruby as an introduction to programming, not just to Ruby in itself.
The examples you give are equivalents to Enumerable#map, not Enumerable#each. In JavaScript, the closest equivalent to #each is Array.forEach(). In C# and Python, while methods equivalent to #each may exist (I'd have to double-check the docs to be sure), the recommended way to accomplish the same functionality as #each is...a for loop.
> More significantly, it has a Parallel.ForEach which is recommended for iterations that can be done in parallel.
Yes and no. I've seen Parallel.ForEach misused more often than I've seen it used right. If you have a small ( < 16) number of loop iterations then don't bother with Parallel.ForEach. If each of those items to process is time-consuming then use tasks and Task.WaitAll for them to complete. Where Parallel.ForEach works well is where there are a very large number of iterations, and the scheduler can split batches of them up between cpu cores, and even tune the batch size as the run progresses. That's just not going to happen when there are 5 loop iterations.
#each and #map are not meant to be the same thing. #each in any language is meant only for side-effects. If you only care about the return value, #map is a much better choice. (Similarly, if you only care about the return value but want many items condensed into one "reduced" item, you want #reduce.)
.each as a concept of "iteration" is transferrable, no?
Also, I think there are some serious consequences when programming is taught in such a "diluted" way.
As a programmer who is constantly learning new concepts/languages, I am continually understanding the very real trade-offs when I write something in Ruby vs. C, not just in functionality, but in the design of the language itself.
By diluting, all languages start to blend in this ball where they become indistinguishable. Besides, if Zed is teaching an introduction to programming, it becomes completely arbitrary what language he chooses, and it therefore means he doesn't need to do variations of his lessons in other languages - unless of course he was going to meaningfully divulge into how these languages propose new ways of approaching a problem, etc. (but this would render this article's arguments moot, to a degree)
I'm an experienced Rubyist. Really. I started using it in 2002.
Depending on the context, I will use a for-loop in my Ruby. Not often, preferring the power that #each provides and backs (e.g., all of Enumerable), but there are times when a for loop is absolutely the clearest way to write what I'm doing.
The only place that I'd change what Zed said with respect to this particular example is that, in Ruby, there are some side-effects to using a for-loop instead of #each. Most of the time, they don't matter, but they do exist. (So in using the for-loop to teach programming, I'd have a footnote that says that the preferred way in Ruby will be discussed later.)
Interesting. Any examples of where you find for more clear than #each? I feel #each is inheritly more clear because it's explicit. Every time I see a for-loop in Ruby I have to remind myself that "oh, that's actually just calling #each". It's also easier going from e.g. #each to #each_with_index, or #each_cons/#each_slice.
Mostly? DSLs and templates. The goal of an in-language DSL isn't necessarily to feel like you're writing that language (I wrote a DSL once that made it easy to generated shared enums for C++, C#, Java, and Ruby. It was Ruby behind the scenes, but because it was declarative, it didn't feel like Ruby. Additionally, the templates used to generate the resulting code almost exclusively used for loops.)
I almost exclusively use the #each-ish in my libraries and in the backing code for such DSLs or templates.
I'm guessing Zed first learned to program using for loops so they look "natural" and easier for beginners to learn than functional callbacks. That seems like a testable proposition, but I'm guessing it isn't so. There aren't too many situations in life outside programming and racing where people go around in circles to get something done. Furthermore, the choice of print in the example begs the question. Are you teaching that imperative programming is natural and functional programming is only for "advanced" students? What are you going to teach the beginner when the goal is calculate the sum of the squares of a list of numbers?
FWIW I learned on BASIC. "GOTO" looks natural to me. It's also much closer to the machine. Structured programming is a prettification of test-and-jump, and you have to be able to see through it, to use it well.
Functional programming, on the other hand, is a bit of a conceptual leap away from the metal. If you're mapping two functions over a stream of data how many loops is it? In a dumb language like Ruby, it will be as many as your map() calls. But in Haskell, it will fuse them into one loop doing two operations. And the thing with functional programming is, you're not supposed to care - except, you do have to. Generating an endless unresolved series of thunks in Haskell is a beginner mistake. But if you can't see through the functional list-flipping to the generation and consumption of callable heap objects in a test-and-jump cycle, you're going to be scratching your head.
My answer would be to teach both assembler and FP, and step up and down simultaneously. Start on Excel and move to Haskell, while also starting on 6502 or some such toy assembler, and moving to C, and meet in the middle at Scheme.
In a very real sense, imperative programming _is_ natural. Its much closer to how computers work. Whether this means that its an easier way to learn is up for debate. (For the record, I think it is easier for a majority of people, but that functional would be easier for a significant minority.) Your phrasing of that part just kind of bothered me.
I think we already teach beginners that you calculate the sum of the squares of a list of numbers with a for loop. Actually, its a fairly common type of problem when you're learning about for loops. Maybe I'm missing your point?
Natural != how the machine works. Few of us have the faintest clue about how the laws of thermodynamics apply to the internal combustion engine or how solid state physics leads to semiconductors leads to electronics leads to electronic injection. Yet we all drive cars as naturally as we walk.
I'd argue that your analogy strengthens my point. In their original form, cars involved people manipulating the mechanical parts as directly as possible (the steering wheel was completely tied to the front axle, the gas pedal, brake, starting crank all directly controlled a single aspect). And yet, we drive cars so naturally. I think using the word natural in this sense makes a lot of sense.
Ruby gets `each` specifically and blocks in general from Smalltalk, so I'd be willing to bet there is research showing whether it is easy or hard to pick up. I'd further wager that the answer is that it is no harder. Loops are more "natural" for the machine, and therefore anybody who understands the machine; that doesn't mean they're more natural for the student.
If you hate that last line, you must hate Unix pipelines as well. Because both accomplish similar things and are surprising to newcomers in a similar way.
I kinda liked it actually. It's a linear sequence of simple operations, and there is an explicit connection between each successive operation (i.e. subsequent operatons are performed on the return value of the last operation).
That's what I personally love about method chaining anyhow.. Functional composition with a structure that's not completely ad hoc is kinda nice.
When I was teaching myself how to program in VBA, I remember thinking "there's got to be some syntax to take a list of things and iterate over each of them." I was of course looking for a for loop (or for each). Without knowing to even google "for loop in VBA", it was a pretty big deal to finally discover, "Hey, programming languages have loops!"
Later, after coding for a couple of years and picking up .NET, I eventually learned LINQ syntax and really started to appreciate the expressiveness of chaining methods together to iterate over collections. It was a nice addition to my tool box, but it still took some practice more me to grok it. If that had been my first exposure to loops, it likely would have been a stumbling block to my learning.
Chapter 12 was 'looping'. I'm not claiming I was some programming genius, but to have been given a computer with a manual that, in < 100 pages spelled out the basic constructs of programming logic... that was magical. And useful. And empowering.
I know we've all got the google at our fingertips today, but I suspect that many people don't even know how to express what they want to do in basic enough terms to search - thedailywtf has examples of that (sadly). I don't know if there's a way to reverse this, but it struck me that we've definitely lost something (or perhaps 'we' never all had it) when you state: 'Without knowing to even google "for loop in VBA"'.
Please, goto/jump .. reminds me of the rant about not being able to implicitely couple two function with global variable mutation in functional programming.
> In the process I've stumbled on what Rubyists call an "idiom", the use of .each to do loops instead of a for-loop. To them this is one of the most important signs that you are a real Ruby programmer. They look at this usage of one looping construct over another as some sign that you are incompetent, and haven't been properly indoctrinated into the Ruby community's ways.
As a Smalltalker, I think select/find/collect/each to be wonderful things, as they are of the same spirit as the do: collect: select: reject: methods in the Smalltalk Collection methods. That said, I find the notion of stigma attached to certain constructs to be counter-productive. In my experience, such attitudes are more about socially scoring points and vying for social dominance than they are actually about improving the community's code. However you get the functionality done is fine, so long as it's short and understandable.
(Such stigma attached to situations where people could use inject:into: but didn't was often counterproductive to readaibility in the Smalltalk community.)
178 comments
[ 3.0 ms ] story [ 151 ms ] threadTo my mind, anyway, using each/collect/inject expresses intent much more clearly than a for loop. If a clearer approach is available, why not take advantage of it?
However, Ruby uses the methods you mention, "collect" and "inject", and these in turn have a few synonyms. And as best I can tell, Ruby's 'filter' variant, 'find' collides with ActiveRecord. What's the general community take on these functions? Which name is commonly used, and how do you do filter in Rails?
Most of them come from Smalltalk's Iterable protocol[0]: that's the source for `select:aBlock`, `collect:aBlock`, `inject:thisValue into:binaryBlock` (Smalltalk uses `fold` when there's no starting value, and `inject` as "fold by injecting initial value"), `detect:aBlock` and `reject:aBlock`.
Smalltalk also uses `do:aBlock` where Ruby uses `each`, likely due to `do` being a keyword in Ruby.
Also, `find` is not `filter` (that's `select`, aliased to `find_all`). `find` is also `find` in Haskell[1] (and maps to Smalltalk's `detect`, also useable in Ruby).
> 'find' collides with ActiveRecord
Uh... no, ActiveRecord collides with Enumerable, I'm pretty damn sure Enumerable came first.
> how do you do filter in Rails?
What's wrong with #find? Or #where? Or #find_by_*? Same name, different namespace, different meaning. Kind-of the point.
[0] http://www.gnu.org/software/smalltalk/manual-base/html_node/...
[1] http://hackage.haskell.org/packages/archive/base/latest/doc/...
It may be the case that at any given point, the idiomatic way is not the fastest. However, if idioms are widely adopted, the language implementers have good reason to optimize them. I'm not saying that's what happened in this case, but I think it's reasonable claim to make in general.
Huh? That is definitely not what it means. That may be a byproduct if the language implementers then make the social mores they admire the ones that perform the best, but otherwise that's not what makes something an idiom or a social more.
I understand the definition of the word idiom. I'm saying that the quoted scenario is, in fact, not just hypothetical, but likely. Thus, following idiomatic style can help one avoid performance issues.
Now "idiomatic" also has two senses. First, it can mean "having to do with idioms". Second, it can mean "peculiar to a particular group, individual or style". (See http://www.merriam-webster.com/dictionary/idiomatic)
So, I think when people speak of idioms regarding programming languages they're using the second of the above senses. While this sense might be characterized as having to do with social mores, I don't think it's a misuse of the word "idiom". People don't mean to say that .each statements are non-compositional in the way that "kick the bucket" is. Indeed, given that programming languages have formal grammars/semantics it's hard to imagine what non-compositionality would be at all (though I'm sure any good Perl programmer could probably give some examples!)
1 : of, relating to, or conforming to idiom
2 : peculiar to a particular group, individual, or style
That again says it's a local construct that isn't a clear universal usage. If you want to be clear in your writing then you avoid idiomatic speech.
This also doesn't disprove my point that the way these supposed "idioms" cause derision and overreaction says they are now social mores.
Idioms, by definition, aren't universal. (By etymology, too: an idiom is idio-, one's own; think idiosyncracy or idiolect.) it. It's very odd to contrast the idiomatic and social mores.
The linguistic analogy is really confused, anyway:
"These idioms are also not language dependent, but actually locality and culturally dependent. I could move to England, the home of English, and they'd use many new and different idioms.
What you don't see is people in England demanding that I say "the dog's bollocks" in order to visit."
1. There is no single language "English" which has its home in England but is also spoken in America, Australia, Canada, South Africa, etc. The contrast between language and locality/culture is extremely tendentious.
2. You had better believe that certain changes of locality and culture are accompanied by demands that one change one's idioms. If I go for a job interview at a conservative law firm, I am not going to praise something by calling it "the shit". If I normally spoke AAVE, I would do my best to suppress that.
3. American English and British English are mutually intelligible (but there are chains of mutually intelligible Englishes whose extremities are not mutually intelligible), so you can speak AmEng in Britain. If you want to speak the way your hosts speak, though, you'll say "boot", "lift", etc. when you would otherwise have said "trunk", "elevator", etc., and you might find that some of your American idioms actually aren't comprehensible. Your British hosts might well demand that you say something they understand to them.
4. You can speak AmEng in Britain, and you can write Fortran in Ruby. It is pretentious for an American to affect an accent while in, or having come from, Britain. By contrast, it is only reasonable to do things Rubyishly in Ruby.
"Because people quite literally freak out when they see non-idiomatic code, and go to great lengths to correct everyone who doesn't write idiomatically, these can't be idioms."
So ... what do you think gets taught in elementary, middle, and high school english classes? Idiomatic formal english! You are corrected if you don't write idiomatically! Many people freak out when they see nonstandard forms of English!
1. a. Peculiar to or characteristic of a given language. b. Characterized by proficient use of idiomatic expressions: a foreigner who speaks idiomatic English.
That use of the word 'idiomatic' is very common, and although it's related to the word idiom, it's not quite the same thing. An idiom, as you say, is a phrase that you can't guess the meaning of just by glossing each of the individual words (a favorite example - in Puerto Rico, though not all Spanish-speaking countries, a flatterer is a 'lambeojo', literally 'eye-licker'). But someone who speaks Spanish idiomatically or who writes idiomatic French does so 'like a native'. It's a good thing. So when someone says that 'each' is 'idiomatic Ruby', that's probably what they have in mind.
All of that said, I can understand wanting to teach beginners the for loop first. But I don't think a Ruby course should finish without looking at each. If a person plans to read any real Ruby, they had better be ready for lots of iteration with each.
[1]: http://www.thefreedictionary.com/idiomatic
Did K&R explain everything about the preprocessor with their "Hello, world!" example? Or the implications of different return codes from main(), what 'return' from a function even means, etc?
Because you aren't teaching, and it merely becomes rote memorization. After all, what does || really mean? What does it do there? Without explaining it, it's magic. And instead of learning, the student must disassociate || with what it really and merely associate it with each.
On top of this, you'll have those wondering what || is, and bothered that they are using something without understanding it's importance.
> Did K&R explain everything about the preprocessor with their "Hello, world!"
No, but they explained what that line (#include <stdio.h>) did. They didn't just gloss over it. They covered every line, and every element, including the different braces.
So, either you teach what || is, or you ignore it, and that will only make things more difficult later on.
That is again another arbitrary social more invented by a rant written by Dijkstra. Learning that a computer processes code by using jumps is an important concept to learn, and it's actually a useful technique in many languages. Saying someone should never learn them is just stupid.
Here's my explanation: the human brain is an identity machine. Apply it intensely to anything over time and you can't help but identify with what you're doing and how. As soon as identity is involved the complete human package kicks in, including emotion and tribalism (banding together with those of like identity in opposition to those of unlike identity). Opposite ways of doing things begin to seem like threats, criticism evokes defensive feelings and so on. If you think you don't function this way, try paying closer attention.
You'd be on more solid ground (and closer to your point about loops) to say that, when teaching foreign languages to beginners, idioms are best avoided because the student is struggling just to know the individual words. Even then, though, I doubt I ever took an introductory language class that didn't teach at least some idioms; you can't get a feel for a language (or fully understand any real-world text) without them.
Maybe from all those classic books on writing, like the "Chicago Manual of Style", "On Writing Well" and "The Elements of Style", which all agree on the point.
Where you got this bizarro impression that idioms are NOT to be avoided in writing? Idioms are cliches, and they needlessly obfuscate a text.
My impression comes from observing language: it is saturated with idioms. You can't throw them all out (without a lot of unnatural effort) nor is there any need to. You might as well say that a musician should use only notes and not chords, or avoid standard chord progressions. If you can find any significant piece of writing that avoids idioms, I'd like to see it.
Idioms are not cliches. An idiom is a phrase whose meaning is more than the sum of its words. A cliche is a phrase that has become hackneyed through overuse. (Nor, by the way, are cliches necessarily obfuscatory. "Get your ducks in a row" is, but "Live and learn" is not.)
Style manuals have their place but are hardly scripture, and there are countless examples of great writers breaking every rule in the book. Indeed, Strunk & White breaks its own rules, sometimes when describing the very rule it's breaking (which is part of its charm [1]). So even if your claim were correct, it wouldn't prove anything. But I'm pretty sure it isn't correct. Since you claim that Chicago, Zinsser, and Strunk & White all agree on the point, please show us where; I'd like to see. All three of those texts are searchable online and I couldn't come up with anything. But I only tried for a few minutes.
[1] Just for fun, here is an example: "Students of the language will argue that try and has won through and become idiom. Indeed it has, and it is relaxed and acceptable. But try to is precise, and when you are writing formal prose, try and write try to." How can anyone not love E.B. White?
So just as reading the simply Yacc grammar for MRI Ruby is not a particularly great plan for mastering Ruby, learning the rules of grammar and memorizing individual vocabulary words isn't going to give you convincing conversational mastery of a spoken language.
Breaking a rule ocassionally is not the same as not having the rule on the first place. For one, they can "break their own rule" precisely because the rule exists. They break the rules they set with caution and only when the feel it is needed. That's the way it is with most rules, about writing or anything else. The rule provide a guideline for the 90% of times.
In fact, don't take my word for it, here's Dave Thomas questioning the .each requirement:
http://video2012.scotlandonrails.com/D2_ML_07-Ruby1280_b.mp4
An "each" block has the scoping you'd expect, and is more consistent with the rest of the Ruby looping constructs (like select/filter or collect/map). It's not a huge deal, but there definitely are technical reasons not to use it.
Could you perhaps provide an example of code using .each that does the wrong thing in 1.8, but the right thing in 1.9?
Looping over a collection object requires some knowledge of its internal state (length in the case of a simple linear structure like Array). In most cases where we use for loops, that information isn't really relevant. There is no need to expose it to the outside world and break encapsulation.
Being consistent in using #each helps when you have complex/custom collection objects where iteration can't be done through a simple for loop. The object might not want to expose its underlying collection and hence can't provide a suitable way to use a for loop on it. Or maybe the collection object has dead elements that it wants to skip and so on. There are any number of reasons to hide the implementation details of the iteration from the external world.
Given this and since Ruby has a powerful block syntax, favouring #each fanatically over for loops, IMHO, is a good thing.
EDIT: I'm also guilty of accusing LRTH with the 'not idiomatic enough' charge in a blogpost I recently wrote for Ruby beginners at http://www.jasimabasheer.com/posts/meta_introduction_to_ruby....
The examples from the article don't make me think I need length or any other internal knowledge to use the for..in loop as opposed to each.
However, the other argument still holds true: In case of a user-defined collection object, 'for..in' will not work since the underlying collection will be hidden.
and HN discussion: http://news.ycombinator.com/item?id=565528
Earlier today I read through Rich Hickey's posts explaining reducers and actually used them to get crazy performance gains from some Clojure code I was writing...but I highly doubt I would've gotten there without Ruby's "each".
I've seen Zed argue on this point before, and I've always been dubious of his "concern". The one point he makes here, though, that makes me side with him is that "for" is easier to teach than "each". Yes. A hundred times: yes!
The point I will disagree with him on is that "for" and "each" are interchangeable. Semantically, yes. Performance-wise, probably. But stylistically, "each" is a gateway drug to functional programming, and that should not be taken for granted.
(Edit: Where this all breaks down, and where I think Zed is experiencing frustration, is that while some people might have had a good reason for using "each", over time it became a social more. Now people teach and even enforce the use of "each" without being able to explain why. That doesn't mean one should avoid teaching "use each, not for", but it does mean that one should go and find out why.)
Start with "for". Teach "each".
...then go learn Clojure because hot DAMN reducers are going to revolutionize the way we program (but that's another topic for another day).
In other words: programmers don't understand pedagogy. Nothing really new there.
I've very much enjoyed the books though...went back and did "Learn C the Hard Way" even though I've been using C for almost 18 years. Can't wait to read "Learn Clojure the Hard Way"... ;-)
FWIW, `for .. in` is syntactic sugar over `each`
There are many.
Some are bigger/louder than others.
In smalltalk there are no loops and no ifs... just methods that are executed on a condition. So 'each:' isn't any more complicated than a 'whileTrue:'.
Just take a look at this Smalltalk examples[1]: ----- [ condition ] whileFalse: [ statements ] [ condition ] ifTrue: [ statements ]
aCollection do: [ :var1 :var2 | statements ] ----
[1] http://www.cincomsmalltalk.com/tutorials/version7/tutorial1/...
Nevertheless, this use of idiom does seem consistent with its normal usage. In the context of natural languages, an idiom can mean a phrase of arbitrary origin that has come to have a specific meaning in specific dialects (this is referred to as an idiomatic expression), but the adjective idiomatic can also be used in the sense of "what sounds most conventional to a native speaker" [1]. Likewise, in programming languages, I think of something as being "idiomatic" if it follows either formal conventions [2] or is a commonly used construct.
As for the author's negative opinion of having idioms in a language, I'd imagine most programmers advocate conventions in order to keep code somewhat consistent across programmers. If you didn't have them at all and if every programmer used different constructs to do the same thing, programmers wouldn't be able to use pattern recognition to read others' code and all code written by multiple people would be even harder to decipher than poorly written Perl since there would be infinitely many ways to do it. TWBIMWTDI? :)
[1] I don't want to say what sounds "right" (hence my use of "conventional") since that would necessitate a lengthy discussion about grammatical prescriptivism, but just note that colloquial expressions like "the people who I gave the ball to" can be considered just as idiomatic (under this definition) as formal expressions like "the persons to whom I gave the ball", even if prescriptivists would define only the latter as "correct".
[2] Unlike natural languages whose syntax is naturally occurring, prescriptivism in programming languages makes sense since they're invented by humans to make writers, readers, and/or revisers of code more productive.
--edited a few times for formatting/clarity
I'm against using .each as a first looping construct. In fact, go look at your supposedly better last line of code and tell me if you think a newbie would even begin to comprehend that? Hell I'm a programming veteran and Ruby veteran and I want to metaphorically punch you in the gonads for that line of code.
I think it'd be kinda cool if one could develop sort of a "ruby-normal-form" that could take some ruby expressions and translate them into a more normalized form using things like for-loops, etc....granted normalizing a lot of ruby code might be hard, intractable, or maybe even impossible.
I don't think .each is so much harder to learn that it justifies getting a beginner in the wrong mindset. Though to be fair I've only ever explained it to people who've already known some programming, so there is a possibility that I'm underestimating the difficulty of teaching it.
In any event, I thought the essay was totally worth the read even if I didn't agree with all of it. Thank you for it.
- First loop programming construct
- Beginner
Exhale. Inhale.
Now back to the blog post and see how many constructs to understand .each correctly vs "just accept it for now that this is how it should work, we'll come back later".
Have you ever read such books? the ones with "we'll come back to it later".
But that was precisely Zed's point! You will certainly end up using it, though you may never use it in Ruby. .each is not transferable, and for-loops are. Zed's teaching Ruby as an introduction to programming, not just to Ruby in itself.
Javascript has Array.map(), which is almost the same:
C# has IEnumerable.Select(): Python has map(), which isn't OOP but accomplishes mostly the same:More significantly, it has a Parallel.ForEach which is recommended for iterations that can be done in parallel.
It's trivial to add it as an extension method though. I've seen it done, and I wanted to punch them for using needlessly overcomplex idioms. It's discussed here http://stackoverflow.com/questions/225937/foreach-vs-somelis...
> More significantly, it has a Parallel.ForEach which is recommended for iterations that can be done in parallel.
Yes and no. I've seen Parallel.ForEach misused more often than I've seen it used right. If you have a small ( < 16) number of loop iterations then don't bother with Parallel.ForEach. If each of those items to process is time-consuming then use tasks and Task.WaitAll for them to complete. Where Parallel.ForEach works well is where there are a very large number of iterations, and the scheduler can split batches of them up between cpu cores, and even tune the batch size as the run progresses. That's just not going to happen when there are 5 loop iterations.
Also, I think there are some serious consequences when programming is taught in such a "diluted" way.
As a programmer who is constantly learning new concepts/languages, I am continually understanding the very real trade-offs when I write something in Ruby vs. C, not just in functionality, but in the design of the language itself.
By diluting, all languages start to blend in this ball where they become indistinguishable. Besides, if Zed is teaching an introduction to programming, it becomes completely arbitrary what language he chooses, and it therefore means he doesn't need to do variations of his lessons in other languages - unless of course he was going to meaningfully divulge into how these languages propose new ways of approaching a problem, etc. (but this would render this article's arguments moot, to a degree)
Depending on the context, I will use a for-loop in my Ruby. Not often, preferring the power that #each provides and backs (e.g., all of Enumerable), but there are times when a for loop is absolutely the clearest way to write what I'm doing.
The only place that I'd change what Zed said with respect to this particular example is that, in Ruby, there are some side-effects to using a for-loop instead of #each. Most of the time, they don't matter, but they do exist. (So in using the for-loop to teach programming, I'd have a footnote that says that the preferred way in Ruby will be discussed later.)
I almost exclusively use the #each-ish in my libraries and in the backing code for such DSLs or templates.
Functional programming, on the other hand, is a bit of a conceptual leap away from the metal. If you're mapping two functions over a stream of data how many loops is it? In a dumb language like Ruby, it will be as many as your map() calls. But in Haskell, it will fuse them into one loop doing two operations. And the thing with functional programming is, you're not supposed to care - except, you do have to. Generating an endless unresolved series of thunks in Haskell is a beginner mistake. But if you can't see through the functional list-flipping to the generation and consumption of callable heap objects in a test-and-jump cycle, you're going to be scratching your head.
My answer would be to teach both assembler and FP, and step up and down simultaneously. Start on Excel and move to Haskell, while also starting on 6502 or some such toy assembler, and moving to C, and meet in the middle at Scheme.
I think we already teach beginners that you calculate the sum of the squares of a list of numbers with a for loop. Actually, its a fairly common type of problem when you're learning about for loops. Maybe I'm missing your point?
That's what I personally love about method chaining anyhow.. Functional composition with a structure that's not completely ad hoc is kinda nice.
Later, after coding for a couple of years and picking up .NET, I eventually learned LINQ syntax and really started to appreciate the expressiveness of chaining methods together to iterate over collections. It was a nice addition to my tool box, but it still took some practice more me to grok it. If that had been my first exposure to loops, it likely would have been a stumbling block to my learning.
30 years ago, I got a computer, and it came with this: http://www.worldofspectrum.org/ZX81BasicProgramming/
Chapter 12 was 'looping'. I'm not claiming I was some programming genius, but to have been given a computer with a manual that, in < 100 pages spelled out the basic constructs of programming logic... that was magical. And useful. And empowering.
I know we've all got the google at our fingertips today, but I suspect that many people don't even know how to express what they want to do in basic enough terms to search - thedailywtf has examples of that (sadly). I don't know if there's a way to reverse this, but it struck me that we've definitely lost something (or perhaps 'we' never all had it) when you state: 'Without knowing to even google "for loop in VBA"'.
:/
As a Smalltalker, I think select/find/collect/each to be wonderful things, as they are of the same spirit as the do: collect: select: reject: methods in the Smalltalk Collection methods. That said, I find the notion of stigma attached to certain constructs to be counter-productive. In my experience, such attitudes are more about socially scoring points and vying for social dominance than they are actually about improving the community's code. However you get the functionality done is fine, so long as it's short and understandable.
(Such stigma attached to situations where people could use inject:into: but didn't was often counterproductive to readaibility in the Smalltalk community.)