6 ms·
One thing I took away from my SICP experience was the idea that it is languages/abstractions all the way down. You can play in a super high level language like
by Xurinos 16y ago
One thing I took away from my SICP experience was the idea that it is languages/abstractions all the way down. You can play in a super high level language like Lisp, or you can mold silicon. Somewhere you have to choose your level of abstraction.
If I am teaching somebody how to think about an algorithm like sorting an array, worrying about memory allocations is tangential, an inconvenient burden C delivers unto us. If I want to teach them about working with memory, pointers, and so forth, C is an excellent language for the job.
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.
We have been mentally shackled by our languages. We think in them. It is hubris to suggest that this the canonical way to think when programming, that, for example, "i = i + 1" is the idiom for incrementing a variable.
I do believe, to be truly effective in our line of work, that our beginners must eventually come to an understanding of the platform upon which they develop. They must understand memory concepts. They must understand timing concepts. They must understand multiprocessing concepts.
But there is no reason to ram C down some poor soul's throat as a first experience. What a terrible language for teaching beginners, full of syntax and slopped-together features. And what a great language to teach somebody in order to prepare them for the industry.
- dkarl 16y agoRuby 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.
- Xurinos 16y agoRuby 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. Vaguely. The "C is close to hardware" point has been well put to rest by folks with better knowledge on the compiler intricacies than I. C gives you the illusion of knowing what you are doing. Your mental model does not help you much in C, at least not in modern C on modern architectures. The next step down from C is object code generated for a specific OS in a specific memory model with a spiderweb of links to other libraries. After that, the OS processes that object code, sending instructions to your hardware, a complicated machine model that includes instruction pipelining, memory pages, and so forth, all of which are difficult to handle by hand without a clear understanding of the interactions. You pointed that out, but you oversimplified the issue. Fortunately, we are rescued from having to have that much understanding by the C language, which abstracts a lot of concepts nicely. I should point out that printf(), the first output anyone learns in C, has its own language for outputing in the form of format specifiers, far removed from direct machine code. Which instruction do you use for "i = i * 2"? a multiplier or a shift? Some developers rewrite malloc() because of various inefficiencies in the way it manages memory, but the beginner can understand malloc() on a very simple level and be successful. The nice thing about ruby, python, perl, java, and many other languages is that you do not have to worry about the memory drudgery. In all likelihood, you are going to do it wrong anyway. If I am teaching beginners algorithms, well, we can focus on memory management techniques later. We can still understand that there is a computer with a CPU and some memory available to us. My point is that you do not have to understand all these layers of abstraction. It is nice to know something of them later, and we are all better developers for it. In fact, knowing a little about garbage collection of your specific language can, for example, help you avoid circular reference memory leaks. When syntax has no pretension to correspond to natural language syntax, it encourages a more appropriate mindset. This is what I mean about being shackled by our languages. We come to believe there is some "appropriate mindset". In fact, the language of choice creates the mindset, and your approach to an algorithm will depend on your ability to translate your will into that language's primitives, means of combination, and means of abstraction. Functional languages are the latest fad in part because programmers in general have rediscovered that method of thinking; as you put it, they have had a "dominant, inappropriate mental model [that holds] back their learning". Our beginners were shown the "i = i + 1" pattern and not shown the "for my $i (1 .. 8) {}" pattern. Sure, natural languages may never be natural enough; two individuals in the same room do not necessarily speak the same English. You have to draw the line somewhere. It just does not have to be at rock bottom, and we have continued to evolve, making layer after layer on top of it. We are corresponding here on a medium that is many levels abstracted from the silicon, and many a beginner in web design can grasp plenty of HTML without understanding how a specific browser is rendering it. I would argue more optimistically that this is not a matter of somebody's learning being held back. They learned and applied a method that is valid. When that method became insufficient, bug-ridden, poorly optimized, whatever, they learned or experimented with a new approach. This is not holding anyone back in any meaningful sense; they are evolving.