Ruby doesn't encourage you think in multiple layers of abstraction. The next step down from C is a simple machine model with instructions, a CPU, and memory, which is actually kind of helpful for writing code and understanding performance. That layer is visible in the design of C. (It's an oversimplification with no concept of caches, buses, instruction reordering, etc., but those can be added to your mental model when desired.) What's the next layer of abstraction down from Ruby? A byte machine and a garbage collector, neither of which are evident in the language design (to a beginner) and neither of which especially helpful to think about while writing Ruby code.

As an abstraction, Ruby just isn't leaky enough. It's too good. It provides no necessity and no reward for thinking about the next layer down. (Plus the next layer down is pretty sophisticated, and pretty abstract from the beginner's point of view. A beginner should know his computer has a CPU and memory and machine instructions, but byte machines and garbage collectors? They will be a mystery until later in the student's development.)

A crazy thing is happening here when we look down upon beginners who want something that feels like a natural language. Why CAN'T we simply say, "I want an app that opens two windows: one with a list of my music files, and the other with cassette controls. Make it so."? Someone could develop a language that does this; AppleTalk, for example, has some crazy high-level stuff similar to this.

Natural language promises are a lie. When you understand the rigid logical nature of a machine, it's fine. There's no disappointment or confusion when the natural language model breaks; you just fall back from your natural language mental model to your mental model of the machine as a logical computing machine. You can do that because you already have that model of the computer as a mindless, mechanical machine.

What happens if you don't already have that mental model? What if your closest familiar model for writing a program is writing instructions for another person? When you don't yet understand the nature of the machine and the nature of programming, natural language-like functionality intentionally misleads you. It tries to hide the nature of the machine from you. It will occasionally fail, and the cumulative effect of dealing with the occasional failures may be that you come to understand that the rigid, uncomprehending behavior that peeks through is the true nature of the machine, but why force a beginner to deal with this now-you-see-it, now-you-don't approach to learning how computers work?

Even worse, a beginner might continue to base his model of the computer on the "normal" humanistic behavior and just write the "failures" off as mysterious, uncharacteristic aberrations. When that happens, a programming language that mimics natural languages is actually much worse for beginners than it is for experienced programmers, because it encourages beginners to stick with a mental model by which the machine will always be mysterious and inscrutable.

Ruby isn't that close to natural language, of course, but I think it's close enough to occasionally revive a beginner's dominant, inappropriate mental model and hold back their learning. I see that phenomenon in myself with the "loop" macro in Common Lisp; lacking a precise understanding of loop, my first impulse is to say things that sound right, write them as code, and then see what happens. I would never actually get it right that way, of course -- it would just be an exercise in random frustration unless I strictly copied a known example -- but somehow it feels like the right thing to do, instead of developing a valid understanding. When syntax has no pretension to correspond to natural language syntax, it encourages a more appropriate mindset.