Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

To me there seems to be something wrong with using as the first language something that depends on a very, very complicated runtime and execution model to run on the hardware we currently are using. This way people end up viewing programming languages as some God-given black box and not just something another computer program written by another person provides for you.

I think CS students should instead start by learning basics of computer architecture at a high level and programming on a level close to the computer architecture that so far has turned out to be practical, the Von Neumann machine. This way they can understand the whole field better, if you never face the challenges of organizing computations in a computer without many existing layers of abstractions designed by other people, you will never understand the development of the field and how the disciplines of algorithms, operating systems, computer architecture, etc came to be the way they are, too many things are taken for granted by people who have only seen very high level languages.

People should know what the stack is, how function calls works, what is an assembler, what linked lists, binary trees, hash maps, ... are and why those had to be invented etc. I think something at the level of Go or C is best for that. Then I think a good moment comes for a course like SICP where people can learn how to take those pieces and build abstraction layers out of them.



Your idea about going from architecture to programming in the other way of traditional curricula, in my opinion, has a lot of merit. Other seem to agree.

An Israeli professor, Noam Nisan, created a course specifically for this purpose, now branded even more popularly as Nand2Tetris course and book.[0]

Why did he teach something obvious like this? From the site:

"Why Bother? Because many CS students don't understand how computers work; because fewer and fewer students take compilation courses; because many computer architecture courses are too detailed and too dry; because nothing beats the thrill of creating something from almost nothing; because Nand2Tetris engages students in implementing some of the coolest algorithms, data structures and techniques in applied computer science, and because the typical student feedback in Nand2Tetris courses is 'the best course I ever took'."

My first exposure to this was at a hackerspace in my area, where far more experienced programmers than I were wrestling with this "hardware and low-level OS layers were a black box" that ever more complex systems and programming environments have created.

I remember being the first time in a while, as an IT guy who plays with open source a lot, I got real enthusiastic even though it was rough for me (I never had a chance to finish). I encourage everyone to look into, because it was designed by Nisan specifically to address the deficiencies you had mentioned, and I watched a lot of skilled hackers fall in love with computers again because of it.

[0] http://www.nand2tetris.org/


A similar textbook[0] is used at UIUC in the Computer Engineering curriculum. I've read both books and I think this one is better, but its not free and its priced like a textbook[1].

[0] http://highered.mcgraw-hill.com/sites/0072467509/ [1] http://www.amazon.com/Introduction-Computing-Systems-gates-b...


One of the best books I've seen takes this approach:

http://www.amazon.com/Code-Language-Computer-Hardware-Softwa...

~

Starting from either extreme (pure maths or pure electrical engineering) is quite healthy--starting in the middle, though, does a disservice.


Ironically, all of the software for From NAND to Tetris is written in Java.


It's not that Java is a bad language to write programs in per se (platform agnosticism can be a huge help for educational purposes). It's just a bad language to teach programming.


It is this kind of nitpicking, without justified analysis of the course (where you do not program in Java, but a language specific to the course for building logic gates and working your way up) and without appreciation for the JVM, Java, and its interaction with the right kind of platform that leads me to believe we missed the entire point of this thread in the comments.


I think you are placing too much emphasis on the start of one's education.

Pick a place in the stack. Start learning. Over time you should go up and down the stack, building understanding as you go.

This can be done from many places in the stack.


The point is that the later courses in CS curriculum depend much more on a good understanding of the imperative model and the issues that first arose in programming early Von Neumann computers, than they depend on understanding functional programming. Undergraduate algorithm classes are exclusively concerned with developing imperative algorithms. Large part of understanding operating systems is understanding how they handle memory management and that there is a need for it in the first place. Computer architecture and compiler courses are concerned with speeding up imperative programs. Even theory of computation courses spend more time exploring Von Neumann - like models than lambda calculus. You could redesign the whole curriculum of course, but then we don't happen to have computers that could more directly and efficiently execute functional programs, so I doubt this is a good idea.


Starting at one place in the stack does not prevent you from moving to other places for subsequent courses.


And you don't see value in the core sequence being more deeply interconnected?


I don't see your approach as necessarily "more deeply interconnected."


That may be true, but it will not be until you descend the stack you start to code like someone who understands what they are doing. For instance I started off with PHP in high school and was using arrays with each entry as a string with a colin in it to split a key and value apart. So essentially I created the worlds worst hashmap and each lookup was O(N) - not to mention the actual string splitting I was doing on each element which would've most likely caused several memory copies.

Why not at least start with some basics at the bottom of the stack and ascend quickly? As Dijkstra mentions he believes a lot of people have had at least small exposure to programming prior to their tertiary education - hence they probably already started at some point in the stack anyhow.


What's the bottom? You clearly have something in mind, but why not starting with logic gates and work up to assembly? That is also a valid approach, and it works up to what you consider the bottom of the stack.

I do computer systems research. I am a big proponent of knowing how computer systems work. But I think people have an unhealthy fetish for how we start learning. You start once. You learn the rest of your life. Where you start is not the most important thing.


Bah. The bottom of the stack is quantum mechanics and solid state physics. From there, you learn how individual transistors work. From that, you build up to logic gates.

I actually know something about those levels. But in 25 years as a professional programmer, the lowest level I've ever actually needed to use was at the gate level (PAL equations to generate chip selects by decoding addresses - if it wasn't in a PAL, it would be just equations).


But many don't do this. Only true artisans due. I did not have this opportunity in college to be taught other way.

I stayed a language major. In hindsight, I would have changed majors, at least double-majored with this kind of curriculum and a few years later with my flirting with Linux. It would have shifted my curiosity in the right direction.

I can do basic Python and Perl programming (not to mention the terrible days of PHP and ColdFusion days in my student jobs), but even as an IT guy I routinely feel I never know enough.

And I am the only IT guy I know, not to program but just to understand, by the Sysinternals Windows Internals 900-pager to even try to get there. And that is just for Windows, which is not even worth it IMHO.


I disagree. The whole point of abstraction is that you don't have to care about the underlying mechanisms (although most non-trivial abstractions are leaky as Joel Spolsky has written about).

For instance, someone who writes assembly should not have to know how a transistor works. A course in introductory programming similarly should not be about how a processor works.


It's trivially easy to write perfectly valid looking Haskell programs that are abysmally slow because of how they are actually executed, and since the reason for this can't be explained at a level of abstraction of such a course, people learn to treat the language as a closed black box, while you can't really competently use any language without understanding its execution model.

Abstractions are fine, but you have to be able to switch the abstractions level when necessary and understand the bits underneath, and I think it's natural to learn starting from low abstractions level and then building up. There are many basic low level issues that surface no matter how high level is the language you are using, I am not advocating teaching assembly to beginners, but a language like C and issues like:

- Direct addressing vs. indirect adressing, aka storing a value vs storing an address, aka pointers vs. values, aka call-by-value vs call-by-reference, ... Beginning programmers brought up on very high level languages are endlessly confused by the difference between copying the value and copying the reference.

- Understanding the stack and how procedure calls work. It might then be easier to understand why tail recursion in functional languages is cool but non-tail recursion not so much.

- Basic memory management. Why data structures are such a big deal.

...

All this shows why abstraction is necessary and useful in the first place, and what it's limitations are.


It's worth noting that Djikstra (to my understanding) thought almost none of that was even contained in the field of CS. His perspective was that CS was about process and verification and proof and thus while the current implementation of computers is interesting, it didn't deserve any privilege.

So being able to prove certain nice properties about algorithms without worrying about the underlying implementation is exactly what Djikstra believed important and something that Haskell does allow you to do... even if the result is abysmal performance.

It's worth noting as well that there's a whole wonderful book [1] that provides a great glimpse of good Haskell style with the conceit that one should program the most abysmally slow correct thing first and then use algebraic theories to transform it along obviously correct paths to something highly performant.

[1] http://www.amazon.com/Pearls-Functional-Algorithm-Design-Ric...


>His perspective was that CS was about process and verification and proof and thus while the current implementation of computers is interesting, it didn't deserve any privilege.

Is that the basis for the quote about "CS isn't about computers any more than astronomy is about telescopes"?

http://en.wikiquote.org/wiki/Edsger_W._Dijkstra#Disputed


"one should program the most abysmally slow correct thing first and then use algebraic theories to transform it along obviously correct paths to something highly performant."

Except that the syntactic variance problem [1] makes this impossible to do in theory. Unfortunately so long we use Turing-equivalent computers there will be a need for "performance programmers" and low-level programming because we cannot automate their job by formal transformations from high-level, "obviously correct" programs (theory proves so).

[1] http://dx.doi.org/10.1145/502175.502181


Well said! Understanding the machine, while useful, does not usually help you solve the problem at hand. A better approach is to teach how to create models, mental and the ones on the computer(datastructures, types etc), and show how that maps to problems at hand. Teaching how to verify models for rigor, efficiency(algorithmic), taste for elegance , and help seeing that computer science is not all that different from math, is what helps you build structures that stand the test of time.


As Brian Beckman explained, as an aside, in "Don't fear the Monad" [1], these two differing views were born in the '70s and split two programmers into two camps:

The bottom-up people, and the top-down people:

- The bottom-up people start with the hardware and only add abstractions and trade performance where necessary (fortran, c, java)

- The top-down people started with perfect abstraction/logic and reduced/removed abstraction to get access to the hardware and performance where necessary (lisp, ml, haskell)

I don't think the two camps may ever get along. Kind of like our version of Conservative and Liberal. (nor should they, in the true spirit of democracy?)

[1] http://www.youtube.com/watch?v=ZhuHCtR3xq8


> The bottom-up people [...] only add abstractions [later]

I don't think bottom-up verses top-down are like political camps. I think it's more innate, like right-brained vs. left-brained.

I can't understand abstractions till I first understand the lower level. I could never learn algebra without first learning arithmetic. (BTW, I'm old enough to have lived through the New Math philosophy which insisted that every grade school text book start with a chapter on set theory before moving on to, say, fractions.) This doesn't mean that I can't start with a functional model, but it does mean that I start with simple functions and move up.


As someone who's strongly in the "top down" camp by observation, I'm about to refute an interpretation of what that means.

Everyone who's learned Haskell really well understands exactly that you learn monads by example, not abstraction. Abstractions need both motivation and "point samples" which describe good reasons for their particular brand of abstract behavior to be meaningful. I don't think at all that the "top down" side actually must work top down, but instead simply values the tools you get when you reach the top, i.e. strong reasoning capabilities and metaphor connections to algebra.

I really want to change the Crockford Monad Curse to instead read that "Anyone who's just learned monads is suddenly incapable of explaining them". When they first "click" you become obsessed with the abstraction as a thing instead of using it as a tool to better leverage patterns which turn up in real examples. Until you shake that by just using monads so frequently that you're damn bored you cannot properly explain them.


Same thing happens with design patterns. It probably happens with all sorts of non-obvious but powerful ideas. Hmm. Any sufficiently advanced learning is indistinguishable from madness?


That's what Plato suggested in his Allegory of the Cave, at least. :-)


I don't think anyone understands abstractions right away. Most people learn through examples, and have to recreate the abstractions themselves, even if the abstraction is explained as well as possible.

I think the main difference is purely in which abtraction people prefer to think in (imperative, OOP, functional, etc) but everyone wants to turn it into something else because to them, their model "feels" more right.


Good points, didn't know about New Math, but the failure is very insightful. I'm not sure if perhaps there should be a distinction between operational abstractions vs logical abstractions.

Scripting seems sit in a strange middle ground. Scripting languages tend to be very high level, but are often very approachable for beginners, e.g. Logo


I don't agree. There's many a programmer I know that can troubleshoot a tube radio, then go write some Lisp. Most are old school folks that grew up in the 8 bit days of solder and wirewrap.


Individuals do both, yes, but disagreeing that there are in fact camps is something else.


people learn to treat the language as a closed black box, while you can't really competently use any language without understanding its execution model.

I wonder if there isn't an opportunity here. Azul's Zing VM's incremental GC basically compensates for cluelessness about how to architect and tune a GC'd language project for high performance. The first reaction might be against such cluelessness, but isn't GC that doesn't require arcane knowledge for high performance a better GC, according to the goals that GC was developed for in the first place?


Changing naive recursion to tail recursion is a very common optimization in functional language compilers.


The whole point of abstraction is that you don't have to care about the underlying mechanisms...

As a math person I love abstraction, I love the idealism of not wanting to worry about underlying mechanisms. As a programmer, I would note that virtually all the abstractions which programming has produced are basically failures at that level - programming languages and constructs are invariably "leaky" to the extent that on the intermediate level you wind-up having to worry about underlying mechanism after-all.

On the other hand, I think Dijkstra's wrong about one's first programming experience shaping one irrevocably. There's nothing wrong with learning pure abstraction first and then finding out it never works but there's nothing wrong with learning "bare metal" first and then learning abstraction. I think learning depends on keeping your "mental space" clean more than on what stuff you've done.


In theory, there's no difference between theory and practice--in practice, there is.

All abstractions in computers and software engineering are leaky, and you either learn enough to overcome the limitations of real machines or you learn to regret your ignorance.


Or you learn to claim that you don't actually care about the difference, because you're a theorist. That means that most of the world ignores you as irrelevant, though.


> CS students

I think CS students should be taught computer science, not software engineering.


Pure theoretical computer science is just a weird offshoot of discrete mathematics, mostly, right?

The central concession of Computer Science as correctly taught is that a purely theoretical approach will not enable you to do anything of use--while you're still finishing your existence proof, some asshole with Ruby and AWS has already gotten it working "good enough" to get funding and make people happy through trial and error.

Software Engineering is too limited a discipline itself, because it is mostly project management, architecture, and planning--mostly vocational skills learned through (hard-earned) experience.

Computer Engineering is too focused on electrical engineering problems: you can guarantee how data is transferred between registers and how fast signals fan out and whatnot, but what the data is or how it is being transformed matters not.

Computer Science as taught combines both of these things in hopes of producing students that can reason about what they're doing (like mathematicians) and plan projects to execute on that (like software engineers) and to appreciate when actual hardware will choke on it (like computer engineers).

It's a blended subject for a bloody good reason.


Maybe 5% of CS grads at the greatest will ever do CS as a full time job. 95% will be programmers/engineers most of the time. Its nuts that you think we should be teaching the former and not the later in just the same way that law is taught. Instead of teaching the practice, the academic subject is taught which means graduating students require extensive experience.


They should be taught both. Too often do I see people coming out of college with strong theoretical roots and absolutely zero clue on how to use a debugger, a source control system or the slightest idea of how a software project goes.


Then they should have picked Software Engineering instead. There is a reason both exist.


Well the C does stand for computer.


“Computer science is no more about computers than astronomy is about telescopes.”

- Dijkstra

It was just too relevant in this case...


How much weight would you give the opinion of an astronomer (today) who didn't know how to use a telescope?


Many astronomers don't have to use or deal with telescopes, just like not all particle physicists have to know much about accelerators.


I don't know. But I could imagine a theoretical computer scientist that didn't really know how to program, or 'use a computer' (I don't necessarily think that that is likely, but I think it might be possible). I had a TA in an algorithm course who claimed, when asked about which data structure was most appropriate for a certain algorithm, that he didn't really know anything about data structures (his background was pure math).

This might be a useless point in the context of something like an undergraduate degree in computer science, though. I guess it is a matter of how theoretical the program is.


"I disagree." - Turing


A Turing machine is not a computer, it's much closer to a mathematician writing down a proof: read a couple of symbols, scratch head, write down symbol, go back again. It's a mathematical model for following a sequence of steps and closely tied to logic, much more so than it is similar to a computer.


I'm an advocate of assembly language on microcontrollers being an introduction to programming. PICs are great because they are cheap, basic tooling is cheap, and the instruction set is small.

It gives a student a period of getting familiar with computers as machines, rather than brands or software stacks. Plenty of time in the rest of your life for that.


> I'm an advocate of assembly language on microcontrollers being an introduction to programming.

I wish more people had this insight. My understanding of computers blossomed once I found Core Wars back in the day. Curricula like "NAND to Tetris" are probably the way to go when it comes to giving students insights to avoid "black box thinking."


>To me there seems to be something wrong with using as the first language something that depends on a very, very complicated runtime and execution model to run on the hardware we currently are using.

Computer Science is more than just programming. There is a lot of formal theory underpinning this area that has nothing to do with circuits, transistors and microprocessors. CS departments shouldn't just be concerned with training programmers, but also scientists.


The bulk of the formal CS theory is much more related to the imperative model than it is to the functional one, see https://news.ycombinator.com/item?id=7024731


So what. What does that have to do with anything? We're not talking about imperative models vs functional ones. And even if we did, imperative programming has nothing to with what you're suggesting. For example, it is always preferable to explore and study algorithms and data structures in higher-order languages so that you don't get bogged down in irrelevant details.

CS departments are going to structure their programs in multitudes of ways. My point is, there's nothing wrong with not being concerned about teaching first-year undergrads microprocessor architecture and the nitty-gritty of memory management and OS design, but instead starting at another end of the Computer Science spectrum. Being exposed to lambda calculus and functional programming early and even viewing the Haskell run-time as some 'God-given black box' is not a bad idea.


Picking on one small point:

My experience of teaching is that a little knowledge of assembler is a dangerous thing when it comes to modern programming. Writing good code for a modern amd64 processor with deep pipelines and vector instructions has almost nothing to do with teaching simple assembler. Students often get the Idea they should do things like limit the number of local variables they use, not realising c or c++ compiles will turn their code in Single Static Assignment almost straight away.


> I think CS students should instead start by learning [...] programming on a level close to the computer architecture

I heard this idea before, sound interesting. Are you aware of any CS course starting with assembly as intro language?


Depending on the track you take, I think that most programs do offer assembly quite early on. I took an x86 assembly class at a local community college, and then a MIPS-based class while doing my B.S. in EE.

I did things a little out of order though, so maybe it's easy to accidentally (or intentionally) miss assembly for a while.


Your first paragraph seems to be entirely nonsense. Almost everyone was first introduced to a high level language. This did not prevent anyone from understanding that those languages are themselves software, written by people. In fact, you generally have to take a whole course on compilers.


Knowing the single fact that a language is ultimately a piece of software is different from having an intrinsic understanding that each high level construct has to be somehow translated to what the computer can do. Everyone learns the fact "compilers provide programming languages" pretty quickly, but beginning programmers don't get early enough into the habit of thinking how what they write in a high level language translates to what the actual computer does, and they end up with broken programs. Whether you are using Haskell or Java, if you don't understand the execution model it's trivially easy to run into problems with memory management, like reallocating memory over and over when growing collections, exploding the stack via inefficient recursions etc. etc.


And you realize that machine code has to be translated to how electrons are routed right? Do you have a good understanding of how that works?

Embrace abstraction folks.


Yes. Yes, I do. And it makes a tremendous difference.

Abstractions are an absolute necessity without which we could never have built a computer. And may be fine to stay at one level of abstraction for day to day stuff. Knowing the levels below and above however makes it possible to not only use the current one better but to also to navigate the hierarchy and use the best abstraction for a specific task. And design new ones if necessary.

Our CS courses provided exactly this: We looked at single transistors, programmed microchips, implemented a CPU on a FPGA, toyed with kernels and drivers, walked trough the OSI-layers, wrote a compiler, a static code analyzer, used monads and the lambda calculus, learned about turing machines and different computing architecures, abstractions, models and beyond.

It really helps to have the 'whole' picture.


Mostly speculation: Successful CS students are by nature inquisitive. They tend to ask the questions "how does this work." They aren't humanoid computers that need every concept spoon fed to them. Semester one doesn't need to teach the stack from high-level languages to quantum mechanics. It needs to get them thinking about basic concepts such as encapsulation, abstraction, and type safety.


That is a lovely hypothesis, but I believe testing it would falsify it.




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

Search: