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.
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].
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.
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.
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.
>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"?
"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).
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?)
> 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?
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.
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?
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
Around the same time, my alma mater was switching from Scheme to Java for their introductory courses.
Last time I went back to homecoming, it seemed that most the professors were feeling pretty dissatisfied about the decision. One of the big reasons mentioned was that Java's just too big and hairy of a language. They end up spending all their time teaching API quirks and software engineering principles (such as pretty much the entire subject of OOP), leaving little time to focus on much more important basic skills such as breaking a problem into smaller pieces and attacking a problem in an organized manner. Or even simple stuff, like the difference between a value and a variable. They also lamented the loss of a REPL, which is an invaluable tool for enabling (and encouraging) students to experiment and get a better understanding of how a programming language actually works.
For my own part, I wonder if the current cultural unfashionability of OOP isn't somehow a result of the vogue for switching CS programs over to Java around the turn of the century. I find myself thinking that what a lot of newcomers to FP seem to think of as problems inherent to object-oriented programming are really just problems inherent to not having worked your way through SICP during your formative years.
I had my formative education based on SICP and I can confidently say it made me a better (Java and other) programmer. I work with Java every day and I am very productive with it, but teaching it as a first language is foolish imho.
Same here. There are two camps in my "alma mater". Those that think that students should learn programming with a simple and "clean" language, and those that think students should focus on widely used languages.
They too abandoned Scheme which means that student don't learn any functional language. I think it's a shame considering that functional paradigms are getting more and more commonplace. (However, I much prefer OCaml to Scheme).
I can kind of see the point of going for "widely used languages", but if you don't want to use scheme or haskell, then at least go for c, c++, python, or javascript. A Java Hello World requires a ton of OOP boilerplate, and you're stuck either explaining OOP as the very first you do (which is stupid), or asking your students to either ignore the boilerplate or recite it as a magical mantra.
Personally, I'm actually pretty hostile to the "widely used languages" camp. I think that position is founded on an implicit assumption about the students' abilities that is both unkind and unuseful: That they won't come out of the program with solid enough skills and knowledge that they can quickly learn any industry language they need. It also implies that the program has lost sight of its reason for existing. Universities have a responsibility to give their students the kind of academically demanding college-level computer science curriculum they're shelling out those huge heaps of money for. There's nothing inherently wrong with putting together a curriculum that just focuses on ticking off the things that show well on a resume, but if you're going to just be offering that level of education then you should do the honest thing by presenting it as a vocational program and pricing it accordingly.
I think the aforementioned assumption about students's ability to learn a lot of different languages a self-fulfilling prophecy, too. Anecdotally, the fresh-outs I've worked with who are least able to pick up new technologies tend to be the ones who came through programs that focus on widely used languages like Python or Java. They tend to have only acquired a superficial understanding of the tools they were taught in, and have very limited understanding of the underlying principles that they're built on and share with other technologies.
Which isn't to say that students shouldn't be exposed to those languages. For more advanced courses, switching to widely-used languages is an absolute must because those are the ones that tend to have the kind of library support that's necessary if you want to be able to focus on the subject at hand. For example, you're not going to get anywhere in a machine learning class if you're hobbled with a language that doesn't have a really good vectorized math library available. And even without that, schools do still have a responsibility to put a marketable language on their students' resume before graduation day.
I went to the University of Texas right before they made this change and I will say that my Programming Language course using Haskell was one of the toughest classes I took there.
I was barely a novice at an imperative language, and all of a sudden I had the comfortable struts of local mutable state ripped out from under me. Having to solve most problems via recursion was incredibly challenging at that stage and I'd be lying if I said I left that class feeling like I understood Haskell.
That course did have the desired effect that Dijkstra was hoping for though. I never programmed functionally in my coursework after that, but it stuck with me and the feeling that "there is something different out there" in the programming language world has forced me to never be satisfied with one language or one approach to solving a problem in my professional life since then.
A problem I've noticed in my degree is that for a certain percentage of students Java just doesn't stick. I'm in my fourth year now and there are plenty of people who just can't program, because they've only been taught Java, and they didn't get that. It's far too big a language to teach in a semester or two to a previous non-programmer.
Even if it does sink in they rapidly find that the simplified Java being taught at first year undergraduate level is far below the standard required for real world Java programming.
Java is definitely a terrible language for teaching and as a student's first introduction to arrays, memory handling and flow control it's pure terrible. However, Java is incredibly effective as a language for large teams. Since most of the companies coming to hire CS grads are big teams in need of extra hands on their software projects, they are looking for CS grads who know Java. So Java in universities is generally the ivory tower being forced by business constraints to adapt to outside business interests.
My university down here taught in Scheme for the introduction and theory classes, and in Java for algorithms and networking. Seemed to work well as a balance, although I'm not sure if they still do that.
> Java is definitely a terrible language for teaching and as a student's first introduction to arrays, memory handling and flow control it's pure terrible
That's not really a bad thing. First, no beginner is going to be learning about coding OSes so teaching the basics isn't a problem. Secondly, Java OSes are far more common than you'd think, although this was more true of 5 years ago when many phones/smartcards/etc used Java in their OS internals. A lot of the topics in OS concepts would probably be useful if you wanted to hack on OSS Android too. So I don't think there is anything wrong with that book which sounds more like an example and reference book on using Java in OS internals (received mention a shotgun approach).
I don't see any problem with teaching CS concepts in Java. The concepts of message passing or a heap are the same everywhere. I was referring more to the basics of programming where you should either teach at a very low level (pascal is great), or at a very high level (python can work). I think people taught originally in something low level like pascal or C often have the best understanding of memory management and what their instructions are doing.
If I was teaching someone coding, I'd probably start with Pascal (incl inline ASM), then any language based on lambda calculus to get a good understanding of recursion, and then Java in a large team environment so they could understand why encapsulation, delegation and code quality are important. It's a shame more classes don't actually just have all 100 students work together on a single code base - it would be incredibly beneficial. The code would likely be terrible with 100 newbies to Java all hacking in their own required feature to the detriment of everyone else. That would drive the lesson home quick!
> It's a shame more classes don't actually just have all 100 students work together on a single code base - it would be incredibly beneficial
I up-voted your comment as a whole, but I really disagree with this statement. It's reality in many situations, but I think it's a shame that anyone has to work together with a team of 100 on anything, ever. You deal with it, and you solve the problems associated with it, but those are problems of management and process.
The students would learn a lot though. Most CS courses will give theory and practice for algorithms etc, but only give theory for software design. Trying to teach a student how and why it's important to encapsulate logic is generally a losing battle until you put them in a position where it makes sense. It's just a theoretical topic (that sounds like a religion) to not have global state until you dump the student in with 100 others all declaring global state. Same for namespaces and interfaces.
It would be a really interesting experiment even: divide up a big problem into 100 or so features and assign each feature to a random person. Give the students some time to work out who they need their code to communicate with and draw up some simple interfaces. Use github or similar with an account for every student. Make the TAs in charge of accepting pull requests. It could be the main focus of a software engineering course.
EDIT: The students wouldn't necessarily need to work with all 100 others - only the ones whose feature their feature interacts with. eg, 1 student could need to receive input from 5 inputs and calculate some statistics - he would only need to talk to the 5 students who would feed him data, and then talk to the 1 student he would feed data to.
Up until about a decade ago, most CS graduates from MIT were never taught C or Java in any class. They still seemed to do pretty well in the job market. (Mostly it was assumed that if you really liked software development, you would go out and learn one of those languages outside of class, such as from a student-led seminar.)
It's just a business thing. Some large local companies come and talk to the university and say that they need a bunch of CS grads to fit into their business. The HR drone says they need to know Java to be able to integrate into the company quickly. The lecturers get upset. The finance department gets promised a donation, the marketing department gets promised easy job searching for CS students. The ivory tower crumbles a bit and the lecturers teach Java.
Well yes it is easily explained by some love for java, why would that be so unlikely?
Computer Science is a diverse field, and not every CS professor considers mutable global variable an evil to be purged. (In fact, the majority of CS professors can't be bothered to think about such matter. They're busy tuning their neural networks, photorealistic simulation of snowflakes, improvements to TCP or whatever their particular research interest is. The answer to "Java or Haskell?" for them is "whatever that suits my need.")
Ah, yes, I remember those days (different university though). Our first class was programming in Pascal, and all subsequent programming classes were "deriving algorithms and proving them correct"-classes (a la Dijkstra). In other classes, like user interfaces, OO-programming, mathematics, computer systems, all kinds of projects, AI, and so on, the assignments had to be done in a particular language and it was up to us to learn it ourselves in addition to the classwork. So I had to learn and used java, c, c++, Delphi, PHP, prolog, bash, mathematica, matlab, haskell, ASM, python, and latex (although I could be forgetting some DSLs). It was fun though :-)
I think there are 2 ways of teaching programming at the beginning, although I'm not sure which is best.
1. Teach structure and organisation of programming. - Python is a good for this as it's object oriented, but has very little boilerplate and syntax getting in the way of learning. A few universities have done well using Haskell for this instead, and I think that's quite a good option, particular as it introduces types.
2. Teach from the perspective of how a computer works - C is probably the best one for this as it helps students understand how computers work at a more basic level, being closer to assembly and machine code. It also allows for memory to be thought of as a much more basic resource of the machine that users must manage.
Java would be good for teaching data structures and algorithms, but I don't think that should come until after an introductory class using one of the above methods.
That's a problem regardless of the specific language taught first and I say that having personally witnessed the struggles of students who learned in pseudocode (my first semester), Java, Python, and Scheme. Programming requires you to structure your thinking a particular way. It's natural for some people, it's unnatural for others. I tutored a couple dozen people of varying aptitudes through the courses as an undergrad and was suprised at how little a difference Java vs Python made.
I do think that there are better ways and worse ways to teach programming. Brett Victor put out an overview [1] of the topic last year and while that essay in itself isn't the answer, it's at least a better start than anything I ran into as an undergrad.
I already had math research experience with C when I finally took my schools introduction to CS course, and had wrapped my head around pointers and recursion. Java just felt like memorizing a bunch of strings and exceptions.
Dijkstra assumes that students will already have been exposed to imperative languages before joining university, and will appreciate the change. I think that this assumption might leave behind students that have not yet been exposed to any programming (that stuck).
Over in the UK I certainly hadn't encountered anything more complicated than html before I hit university, and was very happy with sticking with Java for the entirety of first year. I had been exposed to C++, ADA(!), Prolog and had an in depth look at Erlang by the time my course finished...
I think that this assumption might leave behind students that have not yet been exposed to any programming (that stuck).
Let me provide some anecdotal counter-evidence: during my last year of high school, I was in a university class where they taught us programming using Haskell (this was in 2000). I observed a fairly consistent pattern - those who had prior experience with imperative programming (me included), had far more difficulty picking up Haskell than those who hadn't.
The girl I worked with (who had no prior experience) was surprised, since "it's just like maths" :).
A hypothesis is that it might be harder because you are learning a bit more: you not only have to learn the new way, but also internally how it relates to the old way.
Despite the fact that I learned imperative style first (as most have) -- I think that functional programming is also a valid start point. I don't know that you necessarily benefited from starting in Java/some other procedural language.
I actually graduated from UT's Comp Sci school and I know many of the "elements" courses (super introductory, even for non-majors) are taught in python. That, I think is a good introduction, but for people in the major, I don't think learning Haskell/functional programming is a stretch at all.
If one can wrap their minds around functional programming (which introduced correctly is actually relatively easy to grasp) -- it will be MUCH easier to learn imperative programming. In the end, any good imperative programming seeks to be modular (s/procedures|methods|subroutines/functions/g), and will liken itself to something you would write in functional programming (loosely couple functions that do a specific task well). Yes there are places this gets hairy (side effects, I/O based operations), but computer science is not about writing procedural code, it's really more about algorithms, which is why 4 year universities are NOT trade schools, but do prepare you for the real world (in that you're not COMPLETELY useless). Program syntax is easy to learn (a skilled faker can just repeat it verbatim), efficiency/correctness/proper data-structure usage is difficult.
I spent my first few undergrad years as a CS major at UT before this change happened, and had no prior experience with programming (I started in '97).
The INTRO-intro CS class at the time actually used Pascal, and was endlessly confusing to me as a cold beginner.
My next course, however, was taught in Scheme, and immediately I felt more at home. And for the first time, I felt like I might have some actual aptitude for programming.
Without that peek into the elegant heart of computer science, I doubt I'd have stuck with it as long as I did.
> Dijkstra assumes that students will already have been exposed to imperative languages before joining university
For those entering CS, this is probably true. But it's also probably true that that's because of the students' own initiative to investigate a topic that interests them.
I think high schools have gone the opposite direction. In the 80s, most high schools had some sort of computer class (often taught on TRS-80s or C-64s). These were introductions to programming taught in Basic.
Nowadays, most high schools still have a computer class. But now its Word, Powerpoint, Excel, and build a (static) web page. (There are, of course, some high schools with much better programs.)
Addendum: High schools also used to teach typing (on typewriters). Now that keyboards are ubiquitous, typing classes have inexplicably been dropped. Go figure.
> might leave behind students that have not yet been exposed to any programming
And good riddance. If you make it to university without exposing yourself to your subject as a matter of passion (and few subjects are more easily approached by hobbyists than programming) you're going to waste your time there.
University is a not a "school" you attend for learning a subject. You can't show up for English Literature if you have never read a novel. You show up at the music department if you don't already play an instrument very well. You can't show up at Zoology if you can't tell a reptile from a mammal. You can't study Economics if you've never heard of Keynes. And you can't study computer science if you can't program a computer.
This was not always the case for programming, but it certainly is today, and I'm not convinced it wasn't too in 2001.
Plenty of computer science students at my (SICP-using) university had never programmed before attending, yet they're great at it. Your attitude is especially damaging to female students, who are even less likely to lack programming experience. Computer science isn't even about programming all that much.
> You can't study Economics if you've never heard of Keynes.
Surely you won't get onto an Economics degree course if you haven't already studied economics in high school? I'm from the UK and there you can study Economics from 15.
Also, surely the interview will ask you about your background knowledge of economics, and if you didn't know who Keynes was you're unlikely to get an offer.
Your presumption that all education systems are similar to your own is not valid, relative value or effectiveness not withstanding. The reality is there are quiet distinct differences generally and between US and Uk in particular.
In the US, a bachelors degree takes 4 years, consists of extensive 'general education' requirements outside of the emphasis area, and generally start with intro courses that are more in depth than what would have been studied in high school. So a background in the particular area is not required.
That's definitely not the case in the UK. For example, the guidelines for applying for Economics at Cambridge state:
"The Faculty does not have standard requirements for subjects other than Maths: in particular A level Economics, though useful, is not a prerequisite."
(FWIW I did mathematics as an undergrad but I considered CS and spoke to CS faculty at various university open days, from what I remember they all considered maths to be the only essential A level for admission.)
High school education in the US typically requires a 1 semester economics course, at most. A one semester or one year government/civics course. Two years of history (US and World, the latter typically being very eurocentric). In the sciences, college bound students will have taken (usually) one year each of biology, chemistry and physics. On the math front they'll have gone through trigonometry, perhaps pre-calculus. For foreign languages they'll have usually taken two or three years of some language (almost universally available: French, Spanish; common: German; some regions or schools will have more options available). For literature (also known as language arts or English) they'll usually have taken three or four years. The first is often a refresher on composition, with reading really being intended only to provide material for discussion and writing assignments. The second and third courses are often region/time specific (American Lit, British Lit, World Lit from 300AD-800AD), the fourth (again, for college bound students) will involve more complex novels and writing assignments.
Knowledge of specific economists is not the norm in the basic college prep curriculum in the US. Students in the IB program (relatively rare, available in major cities so the majority don't have the option) or the AP program will have studied the subjects to a greater depth. At least equivalent to freshman/sophomore college courses in the subject.
For a bachelors degree the students will apply to schools and get in based on: GPA, SAT/ACT scores, extracurricular activities, interview (not used for the average university), and essays. Some schools put all freshmen into the same pot and require them to apply to their major after their freshman year. In that case, it'd be similar to your "Don't know Keynes? Probably won't get an offer." situation. However, that's also not the norm. And once at the school the students can usually change major with ease.
Many of us went into college without the privilege of having a good idea of what we wanted to do with ourselves.
In addition to that, among my circle of friends, it's common to know people who switched majors mid-school because they stumbled upon something they found more interesting - isn't that great? They thought they loved something, but found something they loved even more. Or, I guess they should have just been given the boot instead.
I couldn't disagree more. I started with 'Hrm, this particular attitude could be considered exclusionary for underprivileged kids' and you responded with what appears to amount to 'haha, fuck those guys!'.
I hope that you never make it to any position of authority or influence within education.
That's an extremely elitist and exclusionary attitude you have there. Your post is also "begging the question". According to you, people interested in said subject should already be experts by the time they reach university. This is of course flat out wrong, as there are many counterexamples of people mastering and contributing new knowledge of a subject, many many years after attending university. I think you need a reality check.
It's hardly elitest to say that one should show just the slightest interest in the field they are entering college for - enough so to just pick up a simple book and work through it. I had the same experience, students who had no prior experience not only held back classes for those with much more, they tended to fail miserably in labs and exams.
How, for instance, is the average high schooler going to do anything beyond the most basic research in Aerospace Engineering before getting to college? They may have studied physics and calculus, but without access to the tools of a decent shop they can't build much, and most of the worthwhile texts are written assuming a level of understanding of math (specifically calculus and differential equations) and physics (fluid dynamics, statics, dynamics) that they are unlikely to have encountered. Should they not go into AE as a result and stick with the math or physics that they do have some background in?
It is amusing you bring this up, as AE was my major before switching to computer engineering in the 3rd year (Embry Riddle Aeronautical University). I was extremely excited about it in high school. I bought this book -
Started reading it and the math was way above my head. So I went to my calc teacher and he acknowledged the material was beyond my reach. But then he pointed me to materials to help and offered his time to explain the basics.
This was before there were countless free high quality learning materials online.
Are you going to learn differential equations, statics, dynamics, etc... in high school? Maybe. Probably not. Who cares? That doesn't mean you can't start.
Build a model rocket. Build an RC plane. Dive into more accessible subjects like linear algebra. Learn matlab or octave. I could go on forever.
You would not believe the amount of AE students that struggled - and I mean struggled with Ds through intro to programming with C. I helped many with their homework. Get a leg up and start on that!
This strikes me as in principle somewhat wrong and in practice quite wrong. If American universities expelled everyone whose declared major was not a matter of passion, they would in general be pretty empty.
No I am saying that college is not about "goalposts". I truly now believe that college is not something that should be done solely to further ones career (hence, passionless students). Instead it is something you do because you are genuinely interested in a subject and want to further education. Otherwise you end up in the situation we are in.
If the goal is to have a job, there are better ways of accomplishing that than taking on student debt and pursing something you are not that interested in (or spending lots of money trying to figure out what you enjoy).
That could not be more true. I went to a high school that didn't offer any programming or CS courses, and I didn't even know what coding was until I bought myself a Java book on a whim the summer after my senior year of HS.
At college I started as a Bioengineering major, because I really wanted to make medical devices. I took a CS class in the Spring of my Freshman year and realized that it "clicked" for me and I could go forward with it.
I am now graduating as a Bioengineering and Computer Science dual major and moving to a full time software engineering job at Google next year. I am grateful for the opportunity to learn something entirely new, and I worked my ass off to catch up with the kids who had been coding since they were 12. I don't think that I'm an impostor in the world of CS and I have the additional perspective of not always having known that this is what I want to do.
I started programming my second semester of college, and I just got a full time position with Microsoft starting this summer after I graduate so I beg to differ.
"And good riddance. If you make it to university without exposing yourself to your subject as a matter of passion (and few subjects are more easily approached by hobbyists than programming) you're going to waste your time there."
Guess those kids that cannot afford a computer are S.O.L. in your world.
Most subjects are easier to approach than computer programming just because of cost of entry.
>> University is a not a "school" you attend for learning a subject.
Except for the Keynes thing, the stuff you're talking about is included in classes that every 12-year-old has to take. The analog would be using a computer rather than programming a computer.
Please, don't get me wrong, but why would someone with no programming experience pick compsci?
It's not exactly a sexy career (for every übergeek in shorts with a Macbook Air there is an army of corporate drones with comporate-issue desktops using whatever tools corporate IT mandates, wearing corporate-standard neckties), it's difficult (to do it right) and financial return is far from assured.
If you do it for the money (even if you get good money), you'll lead a miserable life.
I taught many aspiring programmers over my career and it's painful to see the struggle some go through contrasted with the ease the "naturals" have. Programming classes can't turn you into a programmer any more than swimming classes won't make you a fish. A good teacher will help you become a good programmer, but only if you have the knack [1].
What year did you enter university? I know the number of kids exposed to programming before university now is much higher than it was when I entered in 1996. I think it's safe to assume (but would love to have some real data) that most CS freshmen these days have dabbled with at least one of the mainstream imperative languages before they hit uni.
It may be turning around now, but applicants for compsci at Cambridge were apparently getting pretty dire by 2006, and this formed a significant part of the motivation for the Raspberry Pi (http://www.raspberrypi.org/about)
> The idea behind a tiny and cheap computer for kids came in 2006, when Eben Upton, Rob Mullins, Jack Lang and Alan Mycroft, based at the University of Cambridge’s Computer Laboratory, became concerned about the year-on-year decline in the numbers and skills levels of the A Level students applying to read Computer Science. From a situation in the 1990s where most of the kids applying were coming to interview as experienced hobbyist programmers, the landscape in the 2000s was very different; a typical applicant might only have done a little web design.
I joined at about that time and found it noticeable that having experience with C++ and a few other languages marked me out as more advanced than many of the other students.
Also relevant to this discussion is that in the first term we learnt ML, a functional language. This was partially because of advantages in talking about algorithms in it, but also to put everyone on a level playing field and introduce something that even keener students won't have encountered before. We did Java later, which I found much less rewarding.
Strangely I found myself struggling to pick up Standard ML despite having experience in C++ compared to my peers with no programming experience. It seems that they just treated it as math, while I had trouble changing my imperative programming mindset.
In case you're not learning from it, allow me to 'advertise' Coursera's proglang. A third of about sml (after racket and ruby) and it was pure joy, the language core and syntax is very tiny (unlike it's type error messages hehe).
It's an incredible experience when the bit flips in your brain and you start understanding recursion and top-down design. I don't use ML any more, but it's definitely affected my coding and problem solving style :)
Also, I once heard that Larry Paulson stopped going to a certain college's annual computer science dinner because he was hit with a pineapple during a food fight. Bastards.
I have some younger (sigh ;) friends in the UK attending uni CS now and almost no-one actually ever touched a programming language. Computers, sure but programming no. Same as when I went to uni mid 90s; I remember of the 80 students 3 (including me) had programming backgrounds. Most were there because 'you earn a lot' as a programmer. Don't think that much has changed, at least not in some universities. A lot of these people switched to law or psychology after a few months to 1 year because, well, CS is hard enough if you actually have no problem with the practical assignments; people who never programmed generally experienced a lot of pain and had to put in a lot of effort to do them.
2005. Because I'd been exposed to HTML and some scripting, I was able to skip on ahead pretty quickly. I estimate that most of my class (about 100 CS students) hadn't had any prior exposure to programming. They dropped like flies for the first few months.
However, I went to a pretty poor University (ranked ~60th), I have no doubt that the numbers are very different in the top universities.
I'm a second year CS major. That's not a safe assumption. Some of them learn to swim, and some of them drown. A guy in my CS1 class last year (there was no placing out) failed to comprehend the concept of words controlling a computer.
Further evidence is the four class intro sequence steadily had fewer sections (of the same size) with each passing term
This is why the University of Chicago has two introductory programming classes - one for students with experience, one for those without.
Honors Intro to Programming (161) is taught in Haskell and introduces monads 4 weeks in. Intro to Programming (151) is taught in Scheme (well, Racket) and works through How to Design Programs.
I think many degree programs assume you have programmed before even if it is nothing substantial.
I know my university's first class in programming assumes prior experience (though nothing to worry about for a motivated student) and then offers an introductory course in python for students with no experience if they'd like. The University in question is still stuck in Java for the main courses like many other Universities.
I agree. It's nearly impossible to appreciate Haskell as a first language unless you have a strong Math background or you have an exceptional teacher. However once you've done a little programming in another non-functional language the beauty of Haskell is pretty clear.
My old university has a big partnership with MIT, and the first programming course is, I believe, similar to MIT's.
I learned programming with Scheme, in that course, in 2004. I used, without noticing, many techniques I would later have relearn due to a "prolongued exposure to imperative programming". In my semester I used closures, functions as first class objects and lots of recursion.
The following three semesters I forgot all that, for I had to use C, C++ and Java. When, in the fourth semester, I had my AI course in Lisp, I used "let"s and loops for everything. In the middle of the semester, I remembered recursion, and how it made everything better (in Lisp). Later, by myself, I relearned closures, functions as first-class-objects and other stuff.
Having Scheme as an introductory language is good because it put students that came from a IT-technical high-school education equal to general high-school education students (that have never seen programming before). With the "real world" so drowned in imperative programming languages, there are few courses that can justify using a functional programming language. The things I know about FP, I know because I thought myself.
I'm not saying FP is better than imperative programming, is just that both should be (well) taught. (As some other paradigms too, I believe).
Some years ago my old uni, like MIT, changed from Scheme to Python. Python is my favourite programming language. But I'm still not happy with the decision.
As much as I enjoy Dijkstra's wit in general (and I agree with the argument for learning functional languages early), I imagine taking a shot at "Texas's solid conservatism" didn't help his case all that much. For "enlightened" individuals, most left thinking and academic people are really no better at mitigating tribalism, prejudice, and ignorance of other points of view than the far fringes of the right. Perhaps it would have been more effective to appeal to the self interest of the council.
I can't help but notice that the vast majority of commenters are missing the fundamental reason for all this handwringing. The reason isn't language schism (that too, but I'd attach a much smaller weight to it) so much as the schism between corporatism & academia.
Corporate America wants languages that are dumb, easy for corporate drones to assimilate, hard to mess up with, verbose ( verbosity is misinterpreted as documentation in the enterprise) and Java fits the bill from the get-go.
So Java became that. Rather than go down the R&D route, the pipeline became more corporate America oriented.
Haskell has always had very deep roots in academia - the focus on enabling the corporate American drone with Haskell is minimal, close to zero. So what do you expect ? The focus will be on debating types & building theorem provers, not on "how to show big bank's fourth quarter report in 3 colors with 7 columns and subtotals in single widget while data-binding seamlessly occurs in middle tier using enterprise beans built from beanfactoryfactory" - this sort of shit that is commonplace in the Java EE world I inhabited post Sun, would be considered positively gauche in Haskell.
Totally! Djikstra was very aware of this influence and pokes only somewhat subtly at it here. Djikstra believed very strongly in inventing the next group of well-armed intelligent computer scientists—scientists tackling the hardest problems humans have yet discovered by his view. His goals are vastly maligned with what corporate America wants and the choice of language is a tool in the war between those interests.
Exactly. Tooling is extremely political. Do you want to use tools with a low skill ceiling? Are you a control freak who worries about the all of the potential catastrophes that unskilled coworkers could rain down on you?
Perfectly put. I'm having to take a VB.net course to advance to the next level of my high school's CS curriculum, if you could even call it that.
It's painful as hell, and like you said, makes me feel like a corporate monkey who's writing some ugly code for use in some specific pants-on-head retarded enterprise "app."
If you think that kind of work is retarded then don't get fooled by the languages and tools. A lot of the web stuff is just the same as VB. Just because its ruby or clojure doesn't take away from the fact that its just CRUD. Try and get into an interesting domain and don't worry too much about the language they use. Domain, domain, domain.
Don't get too discouraged by its corporate cooties. It's true that the language doesn't have a lot of sex appeal (no dialect of BASIC ever does), but it actually has a lot of cool stuff that's worth exploring. All told, you're actually pretty fortunate to be getting taught in one of the few languages a you might see in a high school curriculum that has decent support for interesting things like functional and asynchronous programming. All in all, VB.NET can take you a lot further than you might expect from its reputation among people who don't know it very well or are still sore about losing VB6.
The worst thing I have observed is colleges choosing Java (and C#) "because that's what the market demand".
When I was in college (1986, engineering, not compsci) students started with 8-bit BASIC and FORTRAN (I mostly skipped classes on BASIC because I had learned to program on my Apple II). One year later, they switched from BASIC to Pascal. Later on, one of the teachers decided to teach APL. It was a wonderful experience because it was a different take on my previous paradigms.
I am not sure what is the best way to teach someone how to program. When I was a kid, you turned your computer on and immediately got to a REPL (one Dijkstra would strongly disapprove, but still a programming environment). IMHO any programming language that demands an IDE or a build system more complex than make (even if hidden behind a shiny GUI) should not be used as an introduction. Paraphrasing Dijkstra, it could damage the young minds beyond repair.
If my Apple II booted into Eclipse, I'd have gone into cinematography.
One of my favorite things about heaving to learn Scheme in my intro CS course was that it put most students on an even footing with regards to already (not) knowing the language. It's awesome to see Dijkstra alluding to that, "it drives home the message there is more to programming than they thought."
I'm having a ball learning Clojure now, and it would be much much harder if I'd never used Scheme. (I've done some functional programming in C++ and Ruby, but I wouldn't have done that if I hadn't done it in Scheme earlier.)
My personal opinion - the best languages for learning are script-able, dynamically typed languages like Ruby or Python. You can build very basic programs in a procedural or functional style, and then get introduced very softly into the world of OO.
Haskell is great in some ways, terrible in others. Like the fact that you can't apply a normal function to a monad, and monads are hidden with do <- syntax, so you need to use monadic functions, and then there's type classes and shit... In Haskell it seems the complexity goes up exponentially and building anything beyond trivial is a huge hassle - no wonder 'design' patterns like FRP seem to be all the rage (while the entire computing landscape is being built on languages like C++ and Java).
Lisp/Scheme are conceptually very simple and easy to learn, but the syntax is hard to follow, and some of the keywords make no sense to someone who's never done any programming.
I personally think Ruby -> Java/C++ would be a great progression, with maybe some SML/OCaml on the side somewhere along the way. I spent way too much time dabbling in various 'trendy' languages like Clojure, Haskell, various Lisps and other FPLs, Ruby and JS/Node, etc... Now I'm at the point where I just want to build things, so I'm using a very practical, OOP, statically-typed, compiled language that many people have already shipped many practical apps with.... Probably not going back to 'trendy' languages.
I agree that Haskell can be difficult coming from an imperative mindset (it is for me too!), and that it takes time to grok monads, but what exactly is difficult about type classes?
And what do you mean "design patterns like FRP"? I'm sure you know there are tons of design patterns that are "all the rage" for C++ and Java (a lot of them dealing with the complexity of doing OOP). Why are you giving those languages a pass?
See all the functions which are funM. mapM, replicateM, etc... For a newbie having to use a different function to apply to a monad vs. a pure function is confusing and not necessary.
I'm just getting confused by the terminology. Those are pure functions too. And you have different functions because they're doing something completely different, operating on computational structures that are different from primitive values the 'normal' functions as you called them operate on.
It's like saying C++/Java etc. are confusing because you can only print certain values, but you can't print the print statement.
The first programming language we learned at university was ML. It was a very simple language for teaching functional programming, it has a minimal syntax that makes some sort of sense and it was likely that everyone was starting off at the same point with it.
Like Dijkstra said, getting these high-level concepts in there early is very important.
I'm a wee bit confused by this. I graduated from UTCS in 1990 (the first time) and was a graduate student and employee of the CS department from about 1992 until 2004-ish.
At no time were the introductory classes in Haskell, to my knowledge.
According to the wayback machine[1], the introductory courses (CS307 at the time) in 2001 were in Scheme, while subsequent courses were in C++. I recall the introductory classes experimented with Miranda briefly.
On the other hand, the typed letter[2] is from the EWD archives. Weird.
I love Haskell and Java. From a high level they are my favorite languages for their respective paradigms, so I think most programmers should at least try to write a simple program in both.
That said, I think people are overreacting to Java as a CS 100-level language because of enterprise experiences.
I have written enterprise Java and I hate it, but I still love Java. Java EE is all beans and POJOs and XML and Swing and cruft and I want to burn it in a fire. But that's not Java, those are libraries.
Java is an excellent language to introduce someone to programming, because there is very little magic. Everything is explicit, due to the static typing and imperative nature. The computer (or JVM in this case) doesn't do anything that you don't tell it to do. That's easy for someone to grasp.
Additionally, Java makes it very easy to write readable, organized, and extensible programs even if they are verbose. Using classes, objects, methods, types, and all of that OOP stuff makes it easy to write modular programs where each piece of code does exactly one thing. In functional programming the intricacies of passing state and higher-level functions lead to a lot more spaghetti code for someone who has never programmed before.
Do I think that we should only teach Java? No, of course not. Do I think that it's still a great first language? Absolutely.
If I had control of a curriculum, I'd teach Java for half a semester and then Haskell for half of the semester. I think it's important to not introduce "more productive" dynamic languages like Ruby or Python until students have had to deal with concepts like types so that they can appreciate what Python and other dynamic languages are leaving out.
At Penn, where I go to school, the intro to CS class teaches OCaml in the first half and Java in the second. Unfortunately I think that so many people are struggling with writing code as a concept that they're too frustrated to appreciate the beauty of OCaml at first. Teaching it after something a little easier would make the advantages clearer.
We did half C/C++ and half Mathematica in parallel. For the project you needed to build a prototype in Mathematica and then implement it fully in C++ using a cross platform gui toolkit (Glockenspiel - this was quite some time ago). It seemed to work - for a functional language Mathematica was also fairly practical.
It's just my experience, but the people I know for whom Java was a genuinely first language seem to have a harder time than anyone else grokking pointers.
That's definitely true, but no functional language is going to help with that. Those are only farther from the metal.
The only thing I think Java handicapped me with was understanding pass-by-reference or pass-by-value, but I figured it out when someone told me that Java is "pass by reference by value" meaning that in the method meth(Object obj) { ... } if you do obj.something() you are editing the original object, but obj = newObject won't change the original reference.
I kind of think it's a problem (pedagogically) with Java's model specifically, not purely distance from the metal. I wouldn't be surprised if there were other high-level languages that caused similar trouble, but I also wouldn't be surprised if some did not.
> It is not only the violin that shapes the violinist, we are all shaped by the tools we train ourselves to use, and in this respect programming languages have a devious influence: they shape our thinking habits.
I would guess Haskell would be perfect if the goal is to produce academics. But if most of your students are destined for industry, Haskell is in my opinion the absolute worst language.
- You'll probably get a high drop out rate because of the complexity (recursion, pure / first class functions etc).
- You rely that your students already have experience at high school with imperative languages
- The industry by far still don't use functional languages.
But then again Java is an equally bad choice, for the reasons mentioned, but also you jump immediately into OOP, again expecting the student to have former experience.
What is wrong with laying a solid foundation with the introductory class in C or Python, and then moving on to the more advanced OOP or functional worlds?
Industry is far too low a bar to aim at. College should give them the fundamental understanding of programming that they can apply to a variety of situations. Employability flows out of that.
I truly wish this was a more commonly held view point. You would think, speaking with many, that college was nothing more than a corporate worker mill.
This is a dangerously reductionistic viewpoint that castrates the intellectual potential of students.
To a student versed in Lisp macros, a framework like Rails ceases to be magic and starts being something that can be understood and improved on. Meanwhile, industry shies away from the possibility of a quick dive into a metaprogram, because, (OMG), it's hard!
I'm exaggerating, but industry strikes me as profoundly anti-intellectual at times. We need people to counter this sentiment and the damage it imposes on all of us.
But if the way you're doing it causes a high dropout rate, then you're not giving them "the fundamental understanding of programming" very well, are you? (Unless you're going to be snobbish and say that "only the few can learn this" - but that's a pretty ugly snobbery, especially if it's caused by you choosing an inaccessible teaching approach.)
The dropout rate for entry-level programming courses is high, regardless of starting language. Symbolic thinking is rough to pick up in a single semester. I think most people can get it, but the timeframe is tough, especially on non-majors. I don't know enough to comment beyond this, other than suggesting that we can require less of non-major students to ease them in?
> What is wrong with laying a solid foundation with the introductory class in C or Python, and then moving on to the more advanced OOP or functional worlds?
For C at least, you have a hard time with the syntax on first exposure. Unless you want to teach the idea of "Grammar" as a concept as well. "Why doesn't the for statement have a semicolon after it?" is a common question. It's simply an irregular and ad hoc syntax. After working with freshmen learning C as their first language, I am confident it's a terrible starting point. Others might be worse, however.
Given freedom, I would likely pick Scheme as a starting point, with SICP as the text. Regularity of syntax is extremely important - the only thing your mind really should need to worry about is how to reshape itself to the semantic demands of programming.
To your first point, Haskell is less complex than imperative languages. You get to functional by removing things from imperative: mutable state, side effects, et al.
To your second point, case studies indicate that it is actually much easier for people who have no prior experience with programming to learn functional languages than to learn imperative ones. They also show that it is easier for novices to learn functional languages than it is for experienced imperative programmers to learn functional languages.
To your third point, the finance industry uses functional languages quite a bit, and almost every mainstream language has adopted some aspects of functional style (at the very least lambdas and map/filter/fold). Further, the historical trend for the past 50 years has consistently been that mainstream languages adopt new features from functional languages, which means that learning those languages will help prepare you for advancements in whatever language you end up using.
Laying a foundation in C is like teaching how to cut down trees in a first class on woodworking. Yes, the lower-level stuff is important to flesh out a thorough understanding of the subject, but it is absolutely not the correct foundation on which to build pedagogically. Following that notion through to its logical conclusion, rather than starting with C you would start with electrical engineering and only move on to programming after the student had built their own computer from scratch.
> "The industry by far still don't use functional languages."
What industry are you talking about? I note a few programming languages trying to introduce functional programming features into their languages
- The industry by far still don't use functional languages.
Flat-out wrong. The world's most popular language (in terms of lines of code, number of programmers and companies using it) is a functional language: JavaScript.
Here's a positive report on teaching "back to basics" first-semester programming with Java. They only teach procedural concepts and no OO at all. The point is, while Java itself is non-ideal for this and slants towards OO, you can just ignore that part and teach with it anyway.
Lots of people here have raised concerns that the way Java forces class and static declarations is confusing for beginners. Interestingly, the instructors were concerned about that too, but found that students don't seem to mind.
The second major concern being discussed here, that functional programming isn't possible in Java, I think is a non-issue for a true introductory first-semester class, which needs to focus on more basic issues of procedural programming and abstraction. The SICP approach is beautiful and great for already advanced and highly motivated students, but that's honestly a small minority.
(You can find many more examples of reports like this if you search for "CS1", which is the shorthand for intro-to-CS that's used in the CS education literature.)
Ah, I encountered this coming up when various friends were enrolling in computer science courses at Universities. Curriculum either followed an 'engineering' format, a more EE to CS bottom-up methodology, or they followed a top-down thought process.
The reasoning for bottom-up is that there are fundamental aspects of the bottom up approach that truly teach the fundamentals that are necessary to become a great computer scientist/engineer/developer that I don't think any other method provides.
But the top-down approach is appealing for one reason it seems: It's friendly. I would not be surprised if the retention rate for top-down was greater than the bottom-up. Using something like Python, Java, or whatever other conventional blackbox language is easy, comfortable, and immediately demonstrates to a student the power of programming. The practicality of what they learn is evident. Ideally, interest in this would continue down the line. 'This is really cool, but how does Python actually work?'.
Unfortunately, it seems that most people, when presented with a working blackbox, don't care to see how it actually ticks. It takes a certain special someone to open up a watch, disassemble and reassemble it. So who knows how well the top-down carries over into learning the fundamentals.
The bottom-up has the drawback of intimidating the meek. I certainly was one. I would have benefited from a top-down approach, as I am one of the types who like to see how something ’ticks’.
So therein lies a trade off, would you sacrifice the known quality of your curriculum for better retention? Having someone learn something, is better than nothing, but that’s up to people like Prof. Dijkstra to decide.
I think judging programming languages by their features is the same as judging people by their talent and not by their deeds.
Take Java for example. Most people (Dijkstra included) hate it. But look how much Java has accomplished. It's not a coincidence that Hadoop is written in Java. It's not a coincidence that Java is the primary language on Android.
To quote a great man: "Java works. Java captures the essence of the evolutionary spirit"
Same thing applies to PHP, Javascript, and whatever everyone hates.
Couple of years ago I thought that Java was the Devil's invention and the most awful programming language ever. Then I started using Java with Hadoop. And for the first week Java was the most awful programming language ever. Two/three weeks in I was absolutely okay with Java. It worked. And for me that's the only thing that counts.
My lineup was: Intro1/2: C++. Systems: Assembly. Data Structures: C++. Unix Systems: C/perl. Algorithms: C++. Software Engineering 1/2: Java. Networking: Java. Architecture: C/Assembly. OS: C.
SEng1/2 was introduction to Java/design patterns. That's it. It was the largest waste of time. Then, the holy grail, networking! That professor really threw us into the dark sides of APIs and tortured us. Very little direction and ridiculous projects. That's where I 'learned' Java.
Three years later, I cannot remember Java. I do not recall how to handle the Arrays or anything of that nature. I can still rehearse C++ code off the top of my head! There was no functional programming at my uni in _any_ course.
I tend to think Java is a good first programming language, much like Basic and Pascal were the "first programming language" for so many of us back in our youths. Not every high-school offers programming, and of the ones that do there's no guarantee students have actually been properly introduced to programming.
And like all "first programming language"s, it should be discarded as you learn proper languages.
2001ish-era Java was a fine vehicle for introducing programming. Just not much else.
The second programming classes should move in both directions away from Java - to properly academic and expressive languages like Haskell, or getting their hands dirty with the nitty-gritty of C and assembly languages.
What are Java's merits as a first programming language? Keep in mind all of its warts would have to be unlearned later by the prospective student. It can, like Dijkstra argued, introduce unhealthy thinking habits.
Why not a simpler higher-level language as a first language? (pick one, there are lots of simpler languages than Java).
Most of the good "simple high-level languages" are dynamically typed... which is also worth considering - Python would be a fine "first language" too if you were okay with putting off the concepts of static typing into a later course.
But if you wanted to include static typing and were trapped in 2001? I'd be hard-pressed to come up with a better language than Java, at least without getting into some pretty obscure platforms.
I have actually watched every lecture (even the parts with stuff I "knew") and thoroughly enjoyed it. If an entire course was taught like those lectures were, I think you could teach someone a pretty darn good grasp of haskell pretty quickly (I am of course ignoring the part where you learn really basic fundamentals like bits/bytes, data types, references/pointers, etc)
For serious students of the subject, kicking off with an unusual language can be helpful. As another noted: if the student hasn't even started programming prior to college, s/he is likely not of a succeeding mindset as the bulk of other students already grasp programming.
Starting college, I'd already learned assembler, BASIC, and Pascal - all what Dijkstra was warning against over-ingraining; proceeding to C would have been sensible but entrenching. Fortunately Syracuse University then was starting students on something very strange: APL. That was a mind-opener I needed at the time, and recommend such non-procedural/OOP language very early on for serious students.
"if the student hasn't even started programming prior to college, s/he is likely not of a succeeding mindset"
Clearly it couldn't have anything to do with a lack of access to resources, or simply developing an interest in programming later in life than you.
Starting later may make them less likely to succeed, but saying that it is probably because they don't have a "succeeding mindset" is quite a privileged sounding generalization.
Sorry if the "mindset" comment seems offensive. New students unfamiliar with the topic are up against others who have been programming for years already, who (sometimes regardless of opportunity) managed to get programming books from the library/web, found an affordable computer to work on, and despite any/all hinderances made it happen - to wit, a succeeding mindset.
It was a casual comment in a casual conversation. Apologies if it rubbed you the wrong way; please focus on the well-meant point.
I do most of my programming in Java and I'm convinced I want to learn functional programming, just to broaden my thinking. What are some considerations regarding starting with SICP book/Scheme vs. Scala vs. Closure vs. Haskell?
Personally I prefer Haskell because it's pure.
Here's some good book: http://learnyouahaskell.com/
Scala is just Java+FP, so I use it as a replacement for Java development.
You don't want to have to learn how to use a dynamic language effectively at the same time as learning how to do functional programming, so unless you already know python/ruby/similar I'd say you want a strongly-typed language, i.e. Scala or Haskell (or OCaml, which might actually be the best middle ground if you're willing to try it). Haskell would very much be jumping in at the deep end; it's elegant, pure, and forces a very different way of thinking. OCaml is a bit less purist, still quite elegant, and doesn't perform as well as the other two if that's a consideration. Scala is inelegant, but has seamless integration with Java and similar syntax; if you want to start incrementally it's the best choice, but you may find you're slower to adopt a functional style, because you can write "java-in-scala" and it'll work.
I agree with Dijkstra that Haskell should be taught in undergraduate courses. That's where we boil away most of the really bad, theory-ahead-of-practice CS ideas that academe cultivates. And I say this as a lover of both Haskell and universities.
It's not until you've spent several 4am nights getting darcs and hackage to work that you realize no team can succeed without the sort of people who like reality and boring details as much as beautiful ideas. Haskell's culture is anathema to them. (And no, I'm not one of them. I just want my app to compile and my deps to be found.)
I was a freshman at UT in 2002 in their CS program. I wish they had heeded Djikstra's advice. Java with BlueJ was what we were taught from day 1.
To the departments credit, we did end up taking a couple of courses in Haskell (the best one I remember was the course of compilers - we had to write a C lexer in Haskell). It was one of the more fun classes I took (thanks, in a great part, to the professor teaching us).
The first programming language depends a lot on what the purpose is. EWD's purpose is to train mathematicians specializing in computation. For these types of people, Haskell is fine. "Commercial" languages are better for people who want to learn the basics of programming to apply in a job later.
Why not teach assembly language programming so that the student can really understand how a computer works, and teach Scheme so that they can really understand the power of abstraction, recursion, functional programming etc. A later course can be to write a Scheme compiler generating the same asm lang.
It's much better to pick something multi-typed and multi-paradigm like C# and be able to show the difference between static and dynamic, imperative and functional, AOP etc.
I have to say that Java is the absolute worst language for pedagogy. Before people can write "Hello world", they're told they have to write "public static void main(String[] args)", which are presented as magic incantations, "don't worry about those yet". Thus begins the corporate-style coding culture of bashing stuff without understanding it.
The stated reason for starting in Java is so that students can get coding jobs based on one or two CS classes, but two issues come to mind there. First, I generally wouldn't hire someone (in a technology company) who took one CS class and didn't continue-- but at least if she passed an SICP-style course, I'd know that she learned how to think about computational problems. Second, you don't "know Java" when you come out of school. Java is actually highly complicated (in good ways and bad) and the average college student hasn't been exposed to all the mess of it (and that's probably good, because, while OOP means about 20 different things to different people, business-style OOP is cataclysmic).
While I personally agree with teaching something other than Java, there is one big advantage of Java you have overlooked-- as the core language is so simple, bugs caused by incorrect use of the language tend to be "shallow" (bugs caused by algorithmic mistakes can still be very complex of course).
An easy example of this is compile-time errors -- the most complex compile time error you can get of Java tends to be nothing more than "mismatched bracket" or "incorrect function call", whereas even fairly simple Haskell code can produce very complex error messages, and ghci (for example) tends to make things worse rather than better.
Java isn't perfect and has been getting more complicated, boxing & generics for example, but still is not close to the pain one can create in a handfu of characters in Haskell (of course, C++ has the same problem, for different reasons).
Personally, I see Haskell as the C++ of functional language, and therefore would prefer not to teach either Haskell or C++ as a first language.
That requires support external to the language, right? I haven't seen it widely used in the codebases I've worked on, and it adds additional verbosity to an already verbose language. It's yet another argument against Java as a first language.
I've seen plenty of NullPointerExceptions in enterprisey Java to know you generally do get them.
> An easy example of this is compile-time errors -- the most complex compile time error you can get of Java tends to be nothing more than "mismatched bracket" or "incorrect function call"
So, you're saying it's a benefit that the Java compiler doesn't help you out with anything very meaningful? The "complex error messages" are one of the most significant benefits of using Haskell, for me, because it means that the compiler it helping me out with more than just trivial syntax matters.
Except that Scala already is ;). Haskell pretty much sticks to functional programming and resisted adopting other paradigms (e.g. OO via O'Haskell). Scala, on the other hand seems to adopt as many paradigms as C++.
When I used OCaml, I almost never used the object system. I didn't need it.
The "full" OCaml is pretty complicated, but most of the libraries don't force the "O" on you. (That said, if you're going to use OCaml, you should use the Jane Street libraries, which are far better than the standard library.)
I agree with the point, but the argument -- that by arbitrarily ignoring features you come up with a simple core language -- can be applied to Haskell (and pretty much any other language) as well.
If you exclude typeclasses, extensions, and IO from Haskell, you get a very simple language. (I personally find the error messages easy to understand when avoiding those)
Related: how GHC compiles Haskell code, including the "Core" language and lots of desugaring.
I have written quite a bit of Haskell, I'm not sure what you think is wrong with my belief. Also, I like C++ :)
Both are fairly big complex languages with horrible error messages, horrible compile times (if you use template haskell in particular), with a whole bunch of gotchas you have to learn to get good performance (the haskell gotchas are very different, and often based around lazy evaluation / memory bloat). Both have sharp edges that come from being old languages which have evolved over time.
However, both languages are good in practice for actually getting things done.
That is a very common claim from people posting misconceptions that could only arise from second-hand info and a lack of direct experience. I have a very hard time believing it given that you claim haskell is large and complex.
>Also, I like C++ :)
I won't hold that against you.
>what you think is wrong with my belief
Well, everything you just mentioned except the horrible compile times. Haskell is a relatively small language, and is not complex at all. In fact it is quite simple, and very consistent. I don't know what you mean about horrible error messages, and you do not need to learn any gotchas to get good performance. What you need to learn is very simple, very clearly spelled out in the docs, and is no more than you need to learn in any other language. Avoiding unnecessary laziness is no more difficult than avoiding unnecessary strictness. I can't think of a single "sharp edge" haskell has, I suspect we must have different ideas of what a sharp edge is.
> That is a very common claim from people posting misconceptions that could only arise from second-hand info and a lack of direct experience.
Do you think that I, and an apparently large number of other people on the internet, spend our time insulting Haskell without having used it? That some great anti-Haskell conspiracy is being waged by evil groups unknown?
I haven't written large enough Haskell programs to have performance problems myself, but I work with people who have. People who have to keep an empty monad around because removing it doubles the run-time of the program, and make substansal changes to get programs into an acceptable (<16GB) amount of memory. Also, there are plenty of horrible error messages. Having a random google, here's the first one that comes up. While I can just about figure out what it means, it is several levels more complex than anything that would ever come out of Java. Stackoverflow is full of Haskell questions which are "I don't understand this compile-time error I am getting".
It was a PhD student's program, but the problem was verified by more than one knowledgable Haskell programmer. I'll see if I can get them to write it up somewhere!
>Do you think that I, and an apparently large number of other people on the internet, spend our time insulting Haskell without having used it? That some great anti-Haskell conspiracy is being waged by evil groups unknown?
No, it seems like a relatively small group. And I did not suggest ill intentions, merely ignorance. Do you seriously think "some people repeat second hand info about topics they lack experience with" requires a "great conspiracy waged by evil groups unknown"?
>I haven't written large enough Haskell programs to have performance problems myself
So, you are confirming exactly what I said, that you don't have experience and are repeating second hand info. Why then did you feel the need to invent some sort of conspiracy theory nonsense as a rationale for your behavior?
>People who have to keep an empty monad around because removing it doubles the run-time of the program
That statement demonstrates such an obvious lack of understanding that I am almost able to believe you are ill intentioned. That makes absolutely no sense, it is like me saying "C is bad because I have to keep an empty function around or it doubles run time".
>make substansal changes to get programs into an acceptable (<16GB) amount of memory
That is too vague to be meaningful. Were they working with >16GB of data? Did they just have a memory leak? Do you understand that memory leaks can be created in every language?
>Also, there are plenty of horrible error messages. Having a random google, here's the first one that comes up
Are you trolling? That is a trivially simple error message. It is a simple type mismatch, the compiler expected X, it got Y. Which is precisely what it says.
>Stackoverflow is full of Haskell questions which are "I don't understand this compile-time error I am getting".
Stackoverflow is full of everylanguage questions of "I don't understand this error I am getting". That is completely meaningless.
Haskell is a relatively difficult language to try. Introductions and books almost seem to expect you to understand the syntax when you begin. And I/O is introduced late, which makes it hard to play around with.
Learn You a Haskell is an excellent introductory text and I see no way in which it "expect[s] you to understand the syntax when you begin." It walks you through things very explicitly. Yes, IO is introduced late, but it is not necessary for playing around with the language. IO is only necessary for play in languages that don't have a REPL.
I think you are forgetting that everyone who uses haskell has obviously gone through the trying it stage. It is not that hard, I did it. I just had a couple of PHP programmers do it without any problems. LYAH assumes you know very little, and explains things very simply. It gets to IO plenty quick enough, and before that it is showing you how to play around in ghci where you don't need to care about IO.
Just because you should not explain to students what "public static void main(String[] args)" is the first day does not mean that you can never teach them. Actually, if your students cannot understand what this line is after one full class of Java, then the problem is with the teacher, not the students.
> Actually, if your students cannot understand what this line is after one full class of Java, then the problem is with the teacher, not the students.
I think you're dead wrong about that. Assuming somebody with no programming background at all, here is a (definitely not exhaustive!) list of things that must be learned in order to understand that line:
Method visibility, what is a "method", what is a "function", what is a "class", probably what is an "object" (because it is otherwise difficult to understand why a "class" is a useful construct), "static" methods, either need to hand-wave the use of the term "static" for methods associated with a class or know a reasonable amount of history and/or computer architecture, the idea of a "return type", oh, the idea of a "type" come to that, "void" itself, "main" and generally the idea of a program entry point, function arguments, the "String" type, what is a "character", how are characters made into a "String" (arrays and encodings with various amounts of hand-waving), the "[]" syntax, and arrays of arbitrary length.
A class period is, what, 2 hours? No, it doesn't matter how good you are as a teacher, you can barely cover all that material in a single period, let alone do so in such a way that the students have any idea what you're talking about. Teachers finding themselves a month (or three!) down the road telling their students "now you have enough background to go back and understand the very first line of code you wrote!" is absolutely an anti-pattern.
Having learned C and C++ before even touching Java, "public static void main(String [] args)" arbitrarily shoved inside a class is still an aspect of the Java that absolutely annoys the crap out of me. Before you even print "Hello world" to the screen, you're exposed to an obscene amount of opinionated design (classes! classes everywhere!). Given a competent instructor, students should learn to "break out of main()" as quickly as possible. However, the class where I actually learned Java formally had an adjunct professor who would put EVERYTHING into one class so that students wouldn't have to learn about code organization so early (IMO a huge mistake).
All of that aside, I find it amazingly stupid that a best practice for Java has you creating a specific class like MyCoolAppRunner with only one MAGIC function whose only job is to load ANOTHER class to handle the actual app. IMO C and C++ get it right by having main() exist in the ether by itself -- it indirectly abstracts the stack and heap in a way that makes MUCH more sense than the way Java handles things.
The important part is not the 'never.' The important part is that the _very first thing_ you tell new programmers is "Don't worry about this, it's magic, just ignore it."
This sets a certain kind of tone and expectation about programming that's quite poor.
#include <stdio.h>
int main() {
printf("Hello world!\n");
return 0;
}
Woo! Your first program and I count, at most, 2 things that could be described as "magic" for someone who's never seen C before (the stdio library and double quotes being syntactic sugar for an array of chars). Even then, those two things are deterministic, so they won't remain magical for long.
"But what does 'return 0' do?"
"It returns the value zero to the calling process."
"Calling what?"
"The process. Usually it will be the shell."
"Wait, you just said process, what is this 'shell'?"
I strongly disagree with you. Public, static and void refers to three concepts that are not easy to grasp for starters. After a course they might more or less know what is the magic doing but in most cases they don't understand the underlying mechanism.
On the other hand, you will get students distracted by all those concepts and they don't spend time in what it matters on that level (learn how to make the machine to compute)
This doesn't happen in Scheme (for instance) where everything is clear and simple, two qualities that are great for starters and let them to focus in the algorithm part rather on the language shenanigans.
> Before people can write "Hello world", they're told they have to write "public static void main(String[] args)"
Bootstrapping is hard. My introduction was in Fortran, and I had written a couple of sort implementations before I ever learned to enter an array by any means other than hard-coding it into the program. Kernighan and Ritchie did an excellent job with bootstrapping programming concepts in their book on C.
And, somewhat off-topic, but since you mentioned Hello World and I mentioned K&R, it's worth noting that K&R's meaning when they said that Hello World was the first program you should write in any language was that you need to be able to run something. You have to be able to enter the program, compile it, link it, run it. Today a book can offer an example for Linux, one for Windows, and one for Mac and cover nearly everyone. Not so simple in 1978, when K&R first came out, so they basically tell you to get Hello World running with the help of a local expert (perhaps a teacher), and then come back to the book and start learning.
A lot of the arguments against Java seem to focus on "Time-to-Hello-World". While I agree that the first time you execute a program and see those magic words appear on your terminal, I don't think we should judge a language on that. Visual basic has a very short TTHW (esp. if you take into account the time spent on learning about terminal emulators for most languages), that doesn't make it a good language.
If you take an OO programming language as your teaching language, you need to introduce a number of concepts first.
Hr 1: Talk about classes and objects. Introduce the Car and Bike object, that both have the method 'steer()', the attribute 'wheels' and only the car has the property 'hood'. Introduce return types here, as well as arrays.
Hr 2: Then explain how the 'color' on Car is public, while you'd like the accelerate() method to be private.
Hr 3: Explain how some methods and attributes are static. what is a property of the concept 'Car' and what is an attribute of an instance?
In Hr 4 you introduce them to the classes String and System.
Your students will now know:
-class
-public
-static
-void
-String[]
You can now tell them about the 'magic' that makes things start, the 'main' method.
Class MyFirstProgram {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
No magic, and a nice start to becoming a proper OO-programmer.
If you want too teach them FP, Haskell is not a bad way to go. If you want to teach them OO, Java isn't as crappy as people say it is.
There is always a level of hand waving that will go on in any introductory course, for a lot of reasons. You have to keep in mind that the majority of students come from highly different backgrounds.
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.