
Programming Languages Have Social Mores Not Idioms - rsobers
http://learncodethehardway.org/blog/AUG_19_2012.html
======
daviddaviddavid
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!)

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

~~~
kenko
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!

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

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

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

~~~
wging
> _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.

~~~
icebraining
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)

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

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

~~~
SideburnsOfDoom
> 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...](http://stackoverflow.com/questions/225937/foreach-vs-somelist-
foreach/226299#226299)

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

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

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

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

~~~
pbiggar
Read the article.

~~~
ioquatix
Yeah, I did...

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

~~~
evincarofautumn
“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.

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

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

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

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

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

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

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

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

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

~~~
zedshaw
I agree, but that's a totally different topic from what I'm talking about.

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

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

~~~
pacala
> 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?

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

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

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

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

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

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

~~~
tinco
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

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

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

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

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

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

------
jasim
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...](http://www.jasimabasheer.com/posts/meta_introduction_to_ruby.html).

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

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

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

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

~~~
tomjakubowski
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?

~~~
losvedir
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?

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

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

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

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

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

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

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

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

~~~
zedshaw
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>

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

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

~~~
weavejester
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?

~~~
judofyr

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

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

------
elviejo
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/...](http://www.cincomsmalltalk.com/tutorials/version7/tutorial1/vwloops1.htm)

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

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

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

~~~
twelvechairs
> 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'.

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

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

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

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

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

------
jamesbritt
Possibly helpful:
[http://blog.grayproductions.net/articles/the_evils_of_the_fo...](http://blog.grayproductions.net/articles/the_evils_of_the_for_loop)

and HN discussion: <http://news.ycombinator.com/item?id=565528>

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

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

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

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

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

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

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

------
tomjakubowski
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?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

~~~
why-el
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.

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

~~~
why-el
Got it. Thanks for the clarification.

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

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

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

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

------
ScottBurson
_A social more is something that is demanded by a society_

Actually, the singular is "mos".

<ducks>

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

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

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

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

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

