Hacker News new | comments | ask | show | jobs | submit login
Programming Languages Have Social Mores Not Idioms (learncodethehardway.org)
244 points by rsobers on Aug 19, 2012 | hide | past | web | favorite | 171 comments



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!)


Looking at your own linked definition I think you're wrong:

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.


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.

[1]: http://www.thefreedictionary.com/idiomatic


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!


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:

  users.select(&:meets_some_critera?).each(&:update!)
You could totally do that in a for each loop if you wanted. But it isn't really composable. While this works for the basic update...

  for user in users do
    user.update! if user.meets_criteria?
  end
... what if you wanted to then sum up the new account balances? In the first example, you'd just chain on a couple more enumerable methods:

  users.select(&:meets_some_critera?).each(&:update!)
    .map(&:account_balance).inject(&:+)
  
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.

--edited a few times for formatting/clarity


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.


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.


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.


2 keywords:

- 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".


>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.


.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)


each is definitively transferable for many languages.

Javascript has Array.map(), which is almost the same:

    var numbers = [1, 4, 9];
    var roots = numbers.map(Math.sqrt);
    /* roots is now [1, 2, 3], numbers is still [1, 4, 9] */
C# has IEnumerable.Select():

    IEnumerable<int> squares = Enumerable.Range(1, 10).Select(x => x * x);
    /* squares is [1, 4, 9, 16, ...] */ 
Python has map(), which isn't OOP but accomplishes mostly the same:

    names = ["mary", "john"]
    caps  = map(lambda name: name.upper(), names)


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.


C# doesn't have an Enumerable.ForEach (but it does have a List.ForEach).

More significantly, it has a Parallel.ForEach which is recommended for iterations that can be done in parallel.


> C# doesn't have an Enumerable.ForEach

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.


#each can be seen as special case of #map where the mapped function returns its argument.


#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.)


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.


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.


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.


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.


Right. Also, people should learn to swim by first dipping their tippy toes in a bathtub.


Well, maybe they should.


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.


this is not a dig at you specifically, but more a lament about the basics of computing, and what's been lost.

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"'.

:/


I'm sorry, but this post is absolutely ridiculous in every way.

I think most programmers understand what is meant when people say a programming "idiom", just like most people understand that it's OK to call small representative computer graphics "icons" even though they're not physical religious symbols.

Words gain new meanings in new contexts, that's how language evolves. Complaining about it after-the-fact is just stupid. Nobody's going to start calling these "social mores" because of this article.

And as to why ".each" is a horrible looping construct, the only justification is that it's harder to teach. Well, sure, if you're teaching someone programming for the first time it's probably better to start with "for". That doesn't mean ".each" isn't superior for experienced programmers, though. The author doesn't address any of the advantages to ".each".


Your comment is hyperbole in every way. The post made 2 points:

- we should be calling "idioms" "social mores"

- we should teach beginners simpler constructs instead of idiomatic ones, especially `for` instead of `.each` in ruby.

Note that you agreed with his second point.

He has no responsibility to address the upsides of `.each`, since that's not the point of his article. He wasn't talking about advanced programmers, he was specifically addressing why he didn't teach `.each` in his book, and why it shouldn't be taught to other beginner programmers.


How is .each any simpler than a for loop, conceptually they do the same thing.


Read the article.


Yeah, I did...


Not well. It's described for the entire final quarter of the article, in the section marked "Why .each Is A Horrible First Looping Construct".


“for” is the raw loopy stuff out of which other looping constructs are made—it’s fairly arbitrary. If you’re implementing an iteration construct, then by all means “for” is the thing to use. But in normal use it’s best to express your intent through more common, composable constructs such as maps, folds, and zips. There’s certainly less overhead in reading a non-trivial loop written as a composition than one written as a raw “for”.

So I don’t think “each” is any better than “for”—in addition to having uglier syntax in Ruby, neither conveys any more information than the other. It’s the same with std::for_each in C++, present only for consistency with its more meaningful siblings.


I have no dog in this fight, I was just calling out the hyperbole on the ancestor comment.


If you didn't get my intent, the last part of the article which you recommended was highly biased and after reading it I was left questioning the author's motive.


I don't see the bias or any reason to question his motive, so no, your intent was not clear. I think you'll need to spell this one out for me.


He never argued that .each is a horrible looping construct. He calls it a horrible _first_ looping construct, that is to say that its bad for teaching to beginners. Your last paragraph says nothing that contradicts the article in any way. In fact, you beautifully summarized that portion of the article:

> Well, sure, if you're teaching someone programming for the first time it's probably better to start with "for".

That said, I was inclined to agree that idiom has simply picked up a new meaning. That's usually where I fall in debates about changing language. However, your straw man argument almost made me change my mind out of spite.


I just spent the last two weeks learning the Ruby language (but I come from other programming languages).

I'd argue that learning .each vs. normal looping has numerous benefits. First, this is the way most people loop most things in Ruby. More importantly, however, teaching .each enabled me to be more openminded towards learning "yield" and blocks.

In a way, without having learned about .each first, and coming into Ruby with my preconceptions (or no conceptions), I would have been confused. I would have been writing Ruby as if I were writing Python or C, without really understanding the benefits of writing Ruby as Ruby ought to be written.


Learning a new language requires that you adapt your way of thinking. Idioms are a way to familiarize with the spirit of a language.

Starting to teach languages avoiding what makes the language so special is counter productive. As soon as your students know a basic way to program, they won't be inclined to learn the "good way".


I'm not sure how else to say this, but taking things out of context still does not make them wrong. This is about teaching the concept of programming. If you're learning a particular language, yes, use the idioms. If you're teaching someone how to code, teach concepts that cross languages.


We call people that interact with our software 'users' despite the drug connotation. Hardware stores don't say that, heck even pharma companies don't.


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"... ;-)


Just to be pedantic, it is actually the Smalltalk "do:". :)


As is ruby's entire object model basically. It's Smalltalk with a pythonish basic'ish pearlish syntax.


I think Zed misses the point of idioms both in programming languages and in natural language.

Consider this snippet from natural language:

Paul: "Hey nice jacket, looks great on you"

Linus: "Word"

Linus used an idiom to articulate his sentiment. Why? Because the idiom, if used around someone who understands it, offers little uncertainty about the meaning while also being concise.

Linus could have said, "Why thank you. You really didn't have to say that. I appreciate the compliment but I'd rather not spend a lot of time discussing my jacket".

The idiom was useful because it added clarity, both by reducing the excess information going over the communication channel and also by clarifying the intent.

If you use a for loop in situations where the variables used by the loop are needed outside the loop, then there is no reduction in clarity b/c of the choice of a for loop. However, if you use a for loop when the variables used by the loop aren't needed outside the loop, you pollute the code with unnecessary ambiguity.

Ruby 1.8 had this problem with block variable scope and it was fixed in 1.9. Now in 1.9 you can write code like this:

  x = 5
  (1..3).each do |x|
    x = 99
  end

  puts x #=> will print 5


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.


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 agree, but that's a totally different topic from what I'm talking about.


This is a troll, or the author completely lacks any pedagogical skills. The offending (sic) code:

    arr.each { |elem| puts elem }
Explanation: There is a function "each" that applies to arrays. "Each", for each element in the array, binds "elem" to the element value, then executes the body of the code block. The code applies "each" to array "arr" and executes "puts elem" for each element. Concepts: variable, binding, function, block, array. Done.

The prosecution charges:

> Variables

Basic elementary concept, if you don't get this, you should not be coding yet.

> Arrays

Basic elementary concept, if you don't get this, you should not be coding yet.

> Enumerable

I have no idea what enumerable is, but I can read the code just fine.

> Inheritance

I have no idea what inheritance means in this context, but I can read the code just fine.

> Mixins vs. Multiple Inheritance

For lack of better words, wtf is the author talking about?

> Message passing and dispatch.

Ditto wtf.

> Function calls.

Basic elementary concept, if you don't get this, you should not be coding yet.

> Blocks passed to function calls.

Arguably basic elementary concept, in spite of the long tradition of Basic teaching us otherwise. But then Basic taught us GOTO is a good idea, fortunately we've got past that idea eons ago.

> Yielding variables to blocks.

I have no idea what yielding is or how it helps in this context. Still I can understand the code just fine.

> Scope, specifically for blocks.

Scope is a subcategory of variables, if you don't get scoping then you don't get variables, see blurb on "Variables" section.


For starters, you do realize that the author/troll of the article is Zed Shaw right?

The fact that you can read a piece of code doesn't mean that you understand it. The whole point of teaching how to program is to actually get the student to learn what is actually going on, not just get them to a point where they can give a half assed explanation that really doesn't teach a thing. Repeating the line of code with extra words to convey meaning most certainly does not make it a valid explanation.

And then you come along with a list of "responses" to the concepts outlined in the article, out of which you don't even actually understand half of, and completely destroy your initial argument because of it. You complain that Zed is a troll because you can actually read the code easily, when the whole topic of his is actually wether you can understand it. It's a completely different game. You basically just proved Zed right. The problem with teaching .each first according to Zed is that since you don't understand even half of what is going on, you just do things blindly because you've grown to predict the behavior you expect from a specific piece of code.

For dessert I'm gonna "troll" a little bit. 1) If I should know variables, arrays, function calls, blocks passed to function calls (which includes an arbitrary comment about BASIC and goto statements), and scope, before I start coding then how the hell am I supposed to learn those very basic concepts? I mean according to you I shouldn't be coding right? 2) If you really don't grasp the concepts you say you don't understand in the list, you probably don't program for a living and/or have not had to actually teach any programming concepts besides the very basics. If this is the case, I'd argue that you still have a long way to go before actually having the experience to compare both "teaching orders" being compared here. 3) You give me the impression of a guy that has only done a bunch of jQuery and perhaps a Rails tutorial or two... AMIRITE?

I'm sorry if this comes off like a lengthy angry diatribe (rest assured it's not my intention), but you tried to sound knowledgeable and ended up putting your own foot in your mouth. My mother once told me to only open my mouth if I know what I'm talking about. That my friend is my advice for you.


> The fact that you can read a piece of code doesn't mean that you understand it.

Therein lies the troll. Understanding is not figuring out how to derive the code from first principles. If that were true, you shouldn't drive a car because you can't explain the carburator mix ratio on top of your head. Understanding means being able to copy a pattern and adapt it to a new situation. I never wrote a line of Ruby in my life, but I can take the quoted example and tweak it to do something else without ever worrying what mixins are supposed to mean within the Ruby landscape. Proof:

    arr = [1, 2, 3]
    sum = 0
    arr.each { |elem| sum += elem }
    puts sum

    6
http://codepad.org/x5roEPvS

Isn't it nice that I just invented reduce semantics out of something that ostensibly is only a map?


Understanding how to drive vs building a car is the same thing as understanding how to use a program vs building the program. Once again the point is that if you want to learn how to program in a specific language, you need to understand it's concepts and patterns. It's akin to the fact that if you want to learn how to build a car, you need to understand it's mechanics. You can easily take whatever you find in the internet and build a program. Or you could tweak an example to do something else without another care in the world. Guess what? You still don't understand what's happening or why, and because of that the end product will most probably be defective in some way. You still don't know what the point is, you only know that it works. That's OK if you need a quick solution for a small problem, but it's not when your goal in itself is to learn how to program (in Ruby)...

Go ahead and read Zed's article again, only this time do so slowly and with care. Come back and realize two very important things you seem to be missing:

A) This is Zed's opinion about TEACHING a programming language. TEACHING being the keyword. If you want to learn a programming language, you inherently need to understand it. As a small aside, he did write "Learn Python The Hard Way" which was pretty much a success, but don't believe me... he's probably a troll as you say.

B) The discussion is basically that a form of writing a specific block of code is easier to explain than another, although the latter is more widely used and considered the correct. Readability, though important, has little to do with choosing the correct construct to teach as to provide a good balance of the time and effort you need to put into learning.

You want to keep going with the analogies? You shouldn't drive a manual transmission car if you've only driven automatics, the same way you shouldn't deploy code to your clients that you've figured out will give you the results you want when you've never understood what the program is doing on the first place because you made assumptions when you started.


> Once again the point is that if you want to learn how to program in a specific language, you need to understand it's concepts and patterns.

And it's perfectly fine to initally learn that `.each { |name| … }` as a concept for looping over something.

> That's OK if you need a quick solution for a small problem, but it's not when your goal in itself is to learn how to program (in Ruby)...

I'm not sure what kind of new beginners you have taught (or how you learned yourself), but I always find that new beginners rarely know the whole picture anyway. There's nothing wrong with learning techniques without knowing how they work. In fact, we do it all the time: I wouldn't explain metaclasses when teaching about class methods in Ruby (although they are just an example of methods on the metaclass). I learned basic rules of derivates and how you could use them before I learnt why the rules are true; which am I very thankful for as I wouldn't even get why you would muck around with "limit approaches zero".

> If you want to learn a programming language, you inherently need to understand it.

No, if you want to know a programming language, you inherently need to understand it. If you want to learn it you can either do it from top-down (learn about specific code, then learn how they understand), bottom-up (learn about basic concepts, then combine them to real programs) or anything in between.

I'm mentioning this as someone who learnt programming top-down and spent years without really understanding anything. But I had fun! I created stuff! It would be a sad world if you had to understand everything before you were "allowed" to use it.

> The discussion is basically that a form of writing a specific block of code is easier to explain than another, although the latter is more widely used and considered the correct. Readability, though important, has little to do with choosing the correct construct to teach as to provide a good balance of the time and effort you need to put into learning.

Remember that the user has to learn blocks anyway. It's not like blocks is an advanced feature that is only used in looping; it's everywhere in Ruby! The real comparison here is "teach for, teach blocks later" or "teach #each, teach rest of blocks later".


Actually I agree that new programmers are better of starting with .each, and also that experienced ones can also benefit from an overload of .each to change the patterns they are used to. I commented on why I disagree with Zed's decision that each should be taught later before even getting to this "trollish" thread.

Regarding your second and third bullet points: As I've tried to explain before, there is a tremendous difference between someone reading "The Ruby Programming Language" and "The Ruby Way" trying to "learn" the Ruby programming language, and a person who goes from tutorial, to example, to tutorial, to built product. I can certainly relate to the latter since I started learning C and even a little Asm (thank you SoftIce) by myself when I was 12 thanks to a small stint in a cracking group. These days, though, after programming for around 17 years, when I want to use a new programming language I read on it's syntax, it's methodology, it's patterns... Let's do the analogy thing here: If you want to "learn" multiplication as a child, you have two options. Memorize the multiplication tables, since it's improbable that you'll need anything higher, or actually learn the mechanics of multiplication and how to carry numbers up to the next order of magnitude. There are two completely different monsters. In one you learn what you need to do to create something specific. In the other you learn everything there is to learn about a topic to further your understanding of a topic. Learning the how and the why are two completely different things that get emphasized depending on you needs. My point here is that we're trying to discuss the best methodology for the teaching of a language. In a book. Generally meant to leave students with a complete understanding of the subject at matter.

A small aside, I didn't mean ruby blocks on that last section, I just meant block in the general sense. In any case, I totally agree on the last line you typed. And that's what I've been trying to get the OP to understand. I agree to teach each first because of a plethora of reasons I've already discussed here, but I don't agree Zed is a "troll" because he thinks the explanation of core concepts in his book should be more linear.


"OP" here. The troll characterization it earned by throwing things like "Mixins vs. Multiple Inheritance" in the list of prerequisites necessary to understand the .each example, plus the strong "indoctrination" rant that precedes.

One could troll the for do construct example to require understanding of operational semantics, denotational semantics and / or abstract interpretation and gaulois connections, plus deriving the arithmetic rules in the calculus of constructions starting from the simple (sic) datatype definition Nat = Zero | Succ (Zero). All while ranting about the indoctrination in the evil ways of Turing machines.


"Basic elementary concept, if you don't get this, you should not be coding yet."

The target audience of his book has just learned what a variable and an array is. Since the book as advertized as learning "the hard way," it seems to explicitly attempt to give an insight to what the computer is doing when you tell it to do something.

That is, I sure as hell could translate a for loop to psuedo-assembly, and I could probably teach a newbie how to do the same for their mental model. I don't even begin to think how I would teach them what the computer is doing conceptually.

The target audience of his book is not coding yet. What, should we require a comprehension and vocabulary test before they test something out in a REPL?

As such, I would say Zed's pedagogy is sound.


You can teach <array>.each { |<elem>| <code> } exactly as you would teach for <elem> in <array> do <code> end. The .each variant allows the student to discover a rich palette of correlations as he progresses, the for do end variant is a dead end he needs to forget sooner or later. As a student, I know precisely which variant I'd chose. Do you?


So, define a closure in terms that someone who has just learned what a variable is can understand.

"Just memorize this syntax and do it" is not allowed.


My issue here is that the for version is pretty much exactly "Just memorize this syntax and do it"


I already did:

> There is a function "each" that applies to arrays. "Each", for each element in the array, binds "elem" to the element value, then executes the body of the code block. The code applies "each" to array "arr" and executes "puts elem" for each element.


You give a list of things you'd have to teach before you can explain how the #each works, but are you sure you really need to teach how #each works to explain what it does?

I think I would rather teach that #each is a method that iterates over the elements of the array calling the code block for every element.

This only requires you to teach variables, arrays, the if statement, goto/jumps and objects with their methods.

And frankly it being ruby, I don't think it's bad at all to teach objects and their methods, before teaching iterations.

Maybe it's not in line with your hard way philosophy, but explaining for loops with goto/jumps seems a bit abstract to me. Don't you need to explain how instructions are mapped to memory addresses and the instruction register to really do so?

An each method can be explained with a simple recursive function, no need to dive into hocus pocus CPU details.


> explaining for loops with goto/jumps seems a bit abstract to me

I assume you mean "concrete" - goto/jumps is how it's done in the machine code; to get less abstract we'd have to start looking at how the processor is built.


From the vantage point of the Ruby programmer, the only concrete things are the Ruby statements used to model your desired behaviour.

When you're teaching goto/jumps you'd have to either teach another programming language (raw instructions) which would make it more concrete, but would also raise a lot more questions about how Ruby works, or teach goto in terms of Ruby code, which would make it fairly abstract :P


From the OP:

I'm saying teaching [idioms] as if they are the universal truths is bad. I teach them too, but I teach them as if they are just arbitrary bullshit you need in order to code with other people who have been indoctrinated.

While I agree with the general argument Zed's making, I think it's important not to create a false dichotomy where an idiom is either a universal truth or little more than arbitrary bullshit.

There are legitimate reasons to prefer constructs like "each" over for loops and it would be a mistake to let that get lost in the noise.


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'm curious. Zed Shaw writes that forcing beginners to learn these things without having them critically approach the alternatives is equivalent to indoctrination. IE. Python coders "must" write explicit code (although they have the means to write something more implicit/magical), Ruby "must" write .each (when they can do for, while, etc).

To me it seems like there are two consequences.

1) It's a huge burden on the beginner to be effectively aware of all the possibilities of doing things (like looping) in a language, and why one should be used where. In general, when a beginner picks up a language, he should be doing stuff and recognizing the trade-offs of what he's doing. Thus, he culminates critical awareness through choices and reflection of those choices.

I just can't imagine myself learning Python and hearing about doing things in a hundred different non-Pythonic ways. Unless I were to do it one way, and then later discover of my own accord that there is another way I can do it which has its associated cost/benefits.

2) If these "social mores" are indoctrination, and indoctrination is taboo, what if beginners stop writing .each loops? What if Python programmers start writing "magical" code? etc.

Wouldn't these Python programmers fragment the community and alienate/isolated themselves from a community which has firmly established conventions (for good reasons).

Either way, I love that this point has been raised. I've been looking into Ruby especially, and am always fascinated about how different the conventions and styles are.


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.

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....


"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.


In Ruby "for...in" is just syntactic sugar for #each. Try defining your own #each on a random object!


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.

[0] http://www.gnu.org/software/smalltalk/manual-base/html_node/...

[1] http://hackage.haskell.org/packages/archive/base/latest/doc/...


In Ruby, I always use "map" instead of "collect", partially because it's four fewer letters and partially because its intent is a little more obvious.


I'd say that most Rubyists use #select, whereas #find is a more literate alias that few use outside of AR.


They are not synonyms. Find will only find one result.


I have no particular opinion on the "what's right for beginners" part of the article. Regarding the rest, I'd add that these constructs serve as idioms in a general sense, as well as serving as social mores as described in the post. I would add that they have a third, related use (and are an example of another language construct): a shibboleth. Using these constructs indicate that you are part of the group, and (perhaps more importantly) that you've read the docs/canonical material [books, seminal posts] that the group considers important. Whether you consider this a good idea (I do, but with the understanding that it is imperfect and comes with caveats/should only be considered a starting point) likely depends on perspective on such things, but I think it's valuable to understand it.


I think most of us use idiom in programming to mean 'a form of expression natural to a language, person, or group of people: he had a feeling for phrase and idiom.'

The key is 'natural to a language'. Some writers assume they're helping teach a programming language by teaching what the community regards as the most 'natural' solution to a given problem in order to avoid bad habits. In this sense, 'idiomatic' meaning 'using, containing, or denoting expressions that are natural to a native speaker' is an extremely useful phrase because it implies that a native speaker is an experienced programmer who understands both how to use the language effectively and how the wider community uses it.

'Mores' implies the use of a custom by a social group that may or may not be useful. However, in this case, 'each' is an idiomatic use of the Ruby language. The fact it's awkward to teach what makes 'each' work doesn't detract from the fact that it's widely regarded as a better way to iterate over enumerable collections. To me, the fact it draws on such a large portion of the language may indicate that those parts are actually incredibly useful, and in combination can result in succinct and expressive forms that become easy to work with after a certain amount of education.

The distinction between what's difficult to teach and what becomes natural after a certain amount of education is extremely interesting. I suspect accomplished Ruby programmers originally took a leap of faith and just adopted 'each' because they were told to, then later on fully appreciated the underlying implementation. That doesn't make it less idiomatic, it just makes it more difficult to teach.


> 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.)


The more languages I dip into, and the more code I write, the more I realize people tend to just overdo things with no other purpose than to make things more complex. I love simple. My approach is to design the software in my head as if it was a system of independent components. This function does X, this function does Y, here I have a loop that uses function X to get the value that function Y needs to get value A. Never do I sit down and just write code that is "idiomatic". Don't care about it. When I started learning, all I did was write very simple code. Never did I use a class, or any OOP. My code was easy to follow, readable, and could be "translated" to run in any language. And that is one very important thing that I've learned. Design and code should be easy to translate from one language to another without much hassle. One should not rely too much on some language or framework in order do something.

My understanding of software engineering and computer science is that we should design with a clear mental pattern of what we need to build to get something done. This way, if there is some bug, we can trace it back in the design and not in the code. If we designed with the language in mind, then our software would be limited by the language itself. Then the bugs would just be harder to squash, because we now have to adapt our troubleshooting skills to the language and not the problem. In practice, anytime I face some bug, I just sit back and think about the design and not about the languge/syntax/idioms. It commonly takes me but a few minutes to mentally trace back the problem to the source. No debugger needed.

Zed, this is a fantastic piece, and I hope you include it as part of your books. Since you have shown to have such fine understanding of the problems begineers face, you should write a little booklet that should include things like the one mentioned here. Thank you for this post.


The article views only a single definition of "idiom", ignoring several that actually define a "social more".

The useful content of the article is overshadowed by the vainglorious hyperbole.


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.


It's only a sign because the community adopted it as an arbitrary social norm. There's not really any technical reason to choose one over the other.

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


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.


How did .each have weird scoping pre-1.9? I've run across problems with for-loops, but .each has always behaved predictably, even in 1.8.

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?


    a = 0
    [1, 2, 3].each { |a| }
    a # => 3


Ah, thanks for the clarification. I guess that means there are at least two odd things about scoping in 1.8 loops.


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 ]

aCollection do: [ :var1 :var2 | statements ] ----

[1] http://www.cincomsmalltalk.com/tutorials/version7/tutorial1/...


I think Zed is conflating two things, here.

I think that "idiomatic" is correct, as applied to the behavior of programmers broadly. Groups will fall into using the language in particular ways to indicate things that aren't expressly encoded in the language spec. This will frequently happen along language lines but can also happen within a company or a project.

I think that some communities, in particular the Ruby and Python communities, additionally have strong social mores against writing non-idiomatic code.


I disagree about the 'each' being a 'social more' as opposed to 'for'.

The most important thing you will ever learn about conditional loops is that effectively they are all shorthand for combinations of compare statements and conditional jumps in assembly. Past that really, none are more conceptually simple than any other...

So the analogy of 'each' being "piece of cake" to 'for' being "easy" doesn't really hold to me. Nor does the extreme list of 'concepts I'd have to teach to show someone how .each... works'. They both effectively are the same level of abstraction from 'CMP' and 'J__'.

As someone who learned ruby as my first real language, 'each' made a lot of sense to me. It uses fewer words and relates more closely to the english language than 'for...' to my mind. I don't want to say this is the case for everybody, and 'for...' definitely at least has one advantage (cross language use - though I'm not sure this should be of major importance in a ruby tutorial).

But to me this page doesn't really present a convincing argument against the teaching of 'each' before 'for...'


Well, at least in Ruby, there's one way in which each is more abstracted than for; each creates a new scope, while for does not. This actually is a reason I'd prefer to teach each.

On the other hand, I agree with Zed that for is a better abstraction than each, and I disagree that each and for are at the same level of abstraction. If you're approaching it in the abstract, sure, they're both pretty high-level. But each is as close to pure functional as you get and for is plain iterative.

And assembly is iterative, so I'd call for better for giving people a sense of how the metal works. Which, I think, is important for newbies.


> each creates a new scope, while for does not

Yes. Its a bit of a side issue and the OP hardly mentioned it, so I thought I'd ignore it. I can see how in this way you then might see 'each' as more 'abstract', but this difference doesn't back up the OP's main points (eg. the "piece of cake"/"easy" analogy).

> On the other hand, I agree with Zed that for is a better abstraction than each, and I disagree that each and for are at the same level of abstraction. If you're approaching it in the abstract, sure, they're both pretty high-level. But each is as close to pure functional as you get and for is plain iterative.

Firstly, how one abstraction can implicitly be a 'better abstraction' than another I am not sure. Only perhaps because you (individually) understand it better or have used it before it is more useful to you.

Secondly, how is 'each' any less 'plain iterative' than 'for...' when they both do exactly the same thing (iterate)? Also, how is it more 'functional'? To me its more object-oriented in that the object is stated first, but this isn't to say it is less plain or more abstract.

> And assembly is iterative, so I'd call for better for giving people a sense of how the metal works. Which, I think, is important for newbies.

I agree that Assembly is good to learn, but not sure what you mean by calling it 'iterative'.


>Firstly, how one abstraction can implicitly be a 'better abstraction' than another I am not sure. Only perhaps because you (individually) understand it better or have used it before it is more useful to you.

That was clumsy of me. I meant to say that it was a better abstraction for teaching iterative programming, which is a good tool for getting people productive with a minimum of training.

> Secondly, how is 'each' any less 'plain iterative' than 'for...' when they both do exactly the same thing (iterate)? Also, how is it more 'functional'? To me its more object-oriented in that the object is stated first, but this isn't to say it is less plain or more abstract.

When we're talking rich objects instead of simple iterators, we are speaking more abstractly. Now, naturally, you're always using a rich object in a language like Ruby, but it's a lot easier to gloss over that with for.

>I agree that Assembly is good to learn, but not sure what you mean by calling it 'iterative'.

It's full of side effects, you're not working with clean encapsulated objects.

> Secondly, how is 'each' any less 'plain iterative' than 'for...' when they both do exactly the same thing (iterate)? Also, how is it more 'functional'? To me its more object-oriented in that the object is stated first, but this isn't to say it is less plain or more abstract.

More object oriented == more abstract. But that's basically a semantic game and kind of beside the point, which is that there are more principles of computer science lurking in each than in for. That's great if you're teaching computer science, not so much if you're teaching computer programming.


Yeah. But isn't the whole point of high level constructs that you can use and conceptualize them more easily than, and without prior understanding of, what happens at a lower-level? Just like you don't have to learn exactly how CPU registers work to learn C, you also don't have to learn all the principles of computer science behind 'each' before you can use it....

also - maybe you mean 'imperative' rather than 'iterative'?

In terms of 'abstract', I can see where you are coming from that there are more underlying principles and its more abstract from this point of view. From the point of view I was at, they are both referencing the same variables doing the same thing so its the same abstraction from a programmatic(?) point of view. Probably a poor/confusing choice of words on my part...


The reason to use each instead of for loops is for code consistency. Also there are custom objects which require you to use each to iterate.


for is defined in terms of each, so you can still use for on a 'custom object'


I'd argue that using .each is a better choice in both of the most common cases of people wanting to learn ruby. The novice who's learning his first language will probably benefit by being taught early what it's considered the correct way to do a task. A novice can learn other "styles" later, but as a teacher you want to plant the seed in the students brain that .each is the shiznitz. In contrast an experienced programmer will probably come with for loops deeply lodged in his brain. Therefore it's also beneficial to challenge that prelearned behavior to establish the use of patters that are considered "more correct".

A novice needs to learn the most practical and correct way to do things. An experienced developer needs to learn to transpose his current knowledge to a new syntax. Both benefit from being taught the most common or correct syntaxes and patterns.



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.


> 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.


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.


As far as I know, this has been changed in Python 3. See: http://stackoverflow.com/questions/3815359/while-1-vs-for-wh...

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 think perhaps the reason that these have become known as "idioms" is that in older programming languages, there really are idioms. For a classic example, in C we have:

    for (;;) {
    }
to mean an endless loop. This really is an idiom - to people who've "grown up" with it, it says "endless loop" as clear as day, but for everyone else it just looks odd. And C programmers who know the idiom don't tend to look down on someone who instead uses:

    while (1) {
    }
or some other form.


I don't agree as well. For loop is engrained in our brains so deeply that I think next generation of programmers should not be taught it. It took me quite some time to stop using it, even though I write C++ and it is a lot more difficult to write in functional style. Sometimes I'm just forced to use it. Most of the mainstream languages already support constructs from functional paradigm: C++11, C#, even Java got lambda functions. So, I will say no, don't teach for loops. Teach functional programming.


I agree that the .each method may not be the best looping construct to teach first and I agree that some people do get a bit over zealous about which constructs you 'should' be using.

I feel it's definitely a good idea to ensure the reader is introduced to the .each early though. I guess it's taken for granted now as lots of languages have added their own versions of them, however for myself, coming from a language that doesn't have blocks it's a really good way to start to understand how they work.


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.


Perhaps people wouldn't mind jumps so much, if they called them tail calls?


Why would you need to teach inheritance, mixins, message passing, enumerable, etc. to teach .each as a first looping construct? (And why don't you have to teach whatever powers Ruby's for ... in loop to teach it?) That seems to be like saying that before you can teach `main = putStrLn "Hello World"` as a Haskell hello world program, you need to go into the theoretical grounding for monads.


Well, I think it depends on the person who you're trying to teach. I, for one, spent nearly two years before I even started learning Haskell, precisely because I can't bear the thought of using constructs I don't understand. In this two years time I learned OCaml, Scheme and Erlang, not to mention read countless implementations of monads in these and other languages, just so I could start learning Haskell.

As a side effect (haha) I realized that a) a monad is very interesting and useful concept, no matter in which language; b) Haskell "cheats" heavily in order to be able to do I/O (and side effects) and c) it's this cheating (ie. IO part of IO Monad) which makes it hard to understand (I really prefer Clean's approach, where you get explicit 'world' object to manipulate). As a result I don't know when or even if I'll learn Haskell - and it's caused solely by the lack of full, up-front explanation of Haskell I/O model in most (all?) learning materials for the language.

So, for me, yes - you need to teach me "theoretical grounding of monads" and more or you'll lose me. I never read Zed's books, but I think he's targeting people like me, so your criticism is invalid.


And yet Zed seems to think he can teach the basis by which Ruby's for ... in works without laying nearly the same amount of groundwork. That's the real question---why do you need to go over so much in so much detail in the one case, but somehow the other is significantly simpler? (Especially if the second is actually syntactic sugar for the first!)

"As a result I don't know when or even if I'll learn Haskell - and it's caused solely by the lack of full, up-front explanation of Haskell I/O model in most (all?) learning materials for the language."

The IO monad is just like the State monad, except you can't get the State back out. You're passing around RealWorld. (In any event the "theoretical grounding of monads" doesn't tell you anything about IO. It would tell you things about monads in general---monadic bind and return and join, etc. Haskell may be doing weird things with its IO monad, but your objection actually bypasses what I was talking about, which is the category theory shee that Haskell is known for, but is also found in, say, Scala, where IO is not done through a special monad.)

ETA: given that these books are apparently for people who might need to be taught about variables in the first place, I wonder how accurate your conception of how like you they are is, and how much that resemblance applies to the case at hand. To reiterate, I can't really understand why any explanation that would pass muster with Zed for adequately explaining how "for foo in bar" works in Ruby, including the binding of the name foo, the repeated execution of the body, etc., couldn't be straightforwardly adapted to "bar.each { |foo| ... }". Would the adaptation not get into the weeds of the .each method? Indeed it would not. But then, the explanation of "for ... each" also didn't get into the weeds of that. Both should be acceptable if either is.


If you're coming in as a programming novice, "each" and "for" constructs should look equally as foreign, so you may as well teach the standard conventions. It takes longer to unlearn something, than it is to learn.

>You aren't creating programmers, you're creating good little Rubyists.

You should be creating good Rubyists, if you're using Ruby to teach programming.


If your goal is to create programmers, then you should be creating programmers, not good little rubyists/pythonistas/etc


There's no difference between a good rubyist and a good programmer. By definition, a good rubyist will have a solid understanding of algorithms, OO, design patterns and anything else that makes one a good programmer.


I don't see how learning how to use a language according to its conventions makes one not a programmer.


According to Zed in the article, `for` requires fewer concepts to be fully explained, which `.each` only achieves teaching people to be "Good little rubyists".


I don't see how learning either one makes someone less of a programmer. It seems like you have made a false dichotomy.


One must choose between `for` and `.each` (lets assume we agree that teaching just one is the best approach), so you optimize for your goal of "good programmer", over "good little rubyist".


I have never used Ruby (prefer Python/C), but found the Ruby loop example perfectly clear and extremely readable.


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.


The Ruby community does not say "you should not learn iteration using for loops." It says "if you're (still) using for loops for anything but performance reasons, you probably don't understand enough about Ruby to consider yourself an expert."


Interesting distinction between idioms and mores. ( I was not aware of it.) However a difference between social mores and technical ones is, that technical mores can acquire meaning since more time is spend to optimize the preferred way.


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.


It's an example of that particular social more and the canonical example of good vs. bad looping over an array. That's why I used it.


I see your concern, if I was a beginner and I googled around I might be inclined to learn the supposedly good looping which might be difficult.


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.


Got it. Thanks for the clarification.


.each isn't a looping construct. It is mapping function. Looping constructs allow control over the loop iteration. Mapping functions do not.

People probably shouldn't confuse them. Does Ruby actually have a looping function?


Going out on a limb here, but I think "for" is a looping function.


Does it's invocation syntax differ significantly from the invocation syntax of other functions? Is there another function with the same invocation syntax as for? What are for's arguments? What is it's results?

These are all relevant questions when determining if it is a function or not.

Just the simple fact that loop control is determined by a boolean and requires state implies that for isn't really a function.

For what it's worth, I think Zed has a point. If you're trying to introduce a broad array of concepts to a new a programmer, going with a mapping method associated with an iterable is kind of complicated if you want to explain the whole shebang.

Compare map from Haskell, Lisp, Python etc with each. In each of those languages, you only need to introduce:

1) Named values (as variables, or not) 2) Functions 3) Lists 4) The idea that a function can take a function as an argument

You do need all the additional stuff for each that he mentions.

Similarly, in languages that make higher order functions more difficult, and have implicit state, for is an easier thing to explain.


while, until and begin .. end while/until.

And loop, of course.


It seems to me as though this is not so much about removing idioms from code as using only C-family idioms in code (and even then, regressing as closely to plain C as the semantics of the language permit).


A social more is something that is demanded by a society

Actually, the singular is "mos".

<ducks>


[I tried to post this as a comment, but Zed decided to delete it :/]

I think your comparison between for loops and .each is flawed - clearly you don't need to explain all those concepts in detail if at all. A for loop ultimately involves some level of polymorphism on the target collection, at least to the same level as required by the call to .each. I'd say that conceptually they are very similar, with both constructs having specific differentiating features.

Also, .each doesn't eventually become a for-loop in C code. 1/ Neither Ruby nor Python are compiled to C code, and 2/ I wouldn't expect that the respective looping constructs become a typical C for loop, it is more likely they will be implemented in the native op-code (e.g. CPython, Ruby 1.9).

With respect to why .each is fundamental to Ruby, we clearly see some key differences between Python and Ruby in this respect. I think the critical thing is that Ruby tends towards being a functional language while Python tends to be more imperative. We can see this clearly in the types of operations provided by Python, for example, list.reverse() in Ruby returns a copy of the list in reverse order, but in Python it reverses the list in place.

Using .each in Ruby code leads to shorter more concise code in contrast to the corresponding Python code. Whether you feel that you are being judged or not (in a social sense) is probably a matter of who you choose to interact with on that level (e.g. a particular developer community). Have you ever had to use non-idomatic C code? How about non-idomatic Python code? Clearly, a big issue with source code is composition (on a project level) and non-idiomatic code causes many issues in this area.

It is also interesting to note that non-idomatic behaviour plays a role in larger society. For example, choose the GPL and you might receive some complaints from communities that typically use MIT or BSD license. How about real life? If your friend buys you a drink and you don't play the social "ball game" (e.g. behave non-idomatically) you might have social problems in that area too.

I think that ultimately you are confusing a social interaction with a programming language best practice. I don't think either of these things are bad - heck, look at all the company specific coding standards for C or C++ code - but ultimately whether you choose to indoctrinate your students into a particular social circle, or teach them the best practice for a given programming language is simply a matter of perspective; and empowering your students to understand why things are the way they are, rather than simply saying this is the way we've always done things, is ultimately something I think is very important.


yeah, but it's just a social more of the programming community to describe social mores as idioms :-p

Thoroughly agree with the crux of the argument, though. There is too much cargo cult science wih regards to programming practice. eg don't ever use gotos, upper case reserved words in SQL, functions should be no bigger than N lines. This type of thinking cripples our critical faculties, and is to be resisted.


Concepts needed to teach for loops: Variables, Arrays, if-statement, goto or jumps.

Concepts needed to teach recursion: Function calls, if-statement


[deleted]


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.


Please, goto/jump .. reminds me of the rant about not being able to implicitely couple two function with global variable mutation in functional programming.


[deleted]


I am the author of a notable amount of Ruby code. Also, for loops are syntactic sugar for .each in Ruby, so maybe you should go learn Ruby?


Oh, it's you - I'll take your word for it (seriously). I guess I haven't ever really used for in with Ruby, thought about other languages.


An unsurprising response.


I'm pretty sure Zed knows Ruby quite well.

FWIW, `for .. in` is syntactic sugar over `each`


So in order to each `for ... in`, should you have to teach Enumerable, etc?


He also knows the community quite well, as well.


Well, there is no monolithic Ruby community.

There are many.

Some are bigger/louder than others.




Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: