Dijkstra on Haskell and Java (2001)
chrisdone.com
chrisdone.com
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.
Embrace abstraction folks.
Abstractions are an absolute necessity without which we could never have built a computer. And may be fine to stay at one level of abstraction for day to day stuff. Knowing the levels below and above however makes it possible to not only use the current one better but to also to navigate the hierarchy and use the best abstraction for a specific task. And design new ones if necessary.
Our CS courses provided exactly this: We looked at single transistors, programmed microchips, implemented a CPU on a FPGA, toyed with kernels and drivers, walked trough the OSI-layers, wrote a compiler, a static code analyzer, used monads and the lambda calculus, learned about turing machines and different computing architecures, abstractions, models and beyond.
It really helps to have the 'whole' picture.
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.
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.
So being able to prove certain nice properties about algorithms without worrying about the underlying implementation is exactly what Djikstra believed important and something that Haskell does allow you to do... even if the result is abysmal performance.
It's worth noting as well that there's a whole wonderful book [1] that provides a great glimpse of good Haskell style with the conceit that one should program the most abysmally slow correct thing first and then use algebraic theories to transform it along obviously correct paths to something highly performant.
[1] http://www.amazon.com/Pearls-Functional-Algorithm-Design-Ric...
Is that the basis for the quote about "CS isn't about computers any more than astronomy is about telescopes"?
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).
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?)
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.
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.
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
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.
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?
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.
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.
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 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."
I think CS students should be taught computer science, not software engineering.
- Dijkstra
It was just too relevant in this case...
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.
The central concession of Computer Science as correctly taught is that a purely theoretical approach will not enable you to do anything of use--while you're still finishing your existence proof, some asshole with Ruby and AWS has already gotten it working "good enough" to get funding and make people happy through trial and error.
Software Engineering is too limited a discipline itself, because it is mostly project management, architecture, and planning--mostly vocational skills learned through (hard-earned) experience.
Computer Engineering is too focused on electrical engineering problems: you can guarantee how data is transferred between registers and how fast signals fan out and whatnot, but what the data is or how it is being transformed matters not.
Computer Science as taught combines both of these things in hopes of producing students that can reason about what they're doing (like mathematicians) and plan projects to execute on that (like software engineers) and to appreciate when actual hardware will choke on it (like computer engineers).
It's a blended subject for a bloody good reason.
Pick a place in the stack. Start learning. Over time you should go up and down the stack, building understanding as you go.
This can be done from many places in the stack.
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.
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.
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).
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.
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.
http://www.amazon.com/Code-Language-Computer-Hardware-Softwa...
~
Starting from either extreme (pure maths or pure electrical engineering) is quite healthy--starting in the middle, though, does a disservice.
[0] http://highered.mcgraw-hill.com/sites/0072467509/ [1] http://www.amazon.com/Introduction-Computing-Systems-gates-b...
I heard this idea before, sound interesting. Are you aware of any CS course starting with assembly as intro language?
I did things a little out of order though, so maybe it's easy to accidentally (or intentionally) miss assembly for a while.
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.
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.
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.
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).
Edit: I was 22, not 18. Time flies.
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.
Or this one that runs on your browser: http://amber-lang.net/
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.
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.
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.
Sadly, teaching OS classes with Java is a thing: http://www.amazon.com/Operating-System-Concepts-Abraham-Silb...
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!
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.
Of course then you'd have the student that forgot to include SQL injection protections getting their project goat.se'd during a demonstration.
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.
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.")
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.
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.
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...
> 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.
Also Larry Paulson is a legend.
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.
However, I went to a pretty poor University (ranked ~60th), I have no doubt that the numbers are very different in the top universities.
Further evidence is the four class intro sequence steadily had fewer sections (of the same size) with each passing term
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 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.
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" :).
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.)
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.
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.
http://www.studentbeans.com/student-money/a/degree-courses-w...
According to these numbers, of the 2006/2007 graduates in the UK, Computer Science had the highest unemployment rate after 6 months (10%).
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].
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.
> You can't study Economics if you've never heard of Keynes.
Have you ever even been to a university?
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.
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.
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.
"The Faculty does not have standard requirements for subjects other than Maths: in particular A level Economics, though useful, is not a prerequisite."
http://www.econ.cam.ac.uk/ba/guide.pdf
(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.)
http://www.amazon.com/Fundamentals-Aerodynamics-Aeronautical...
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!
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).
I hope that you never make it to any position of authority or influence within education.
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.
Yes, it's quite silly that college is mandatory rather than somewhere you go for the purpose of learning something in further depth.
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.
Thank god you're not in charge.
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.
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.
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 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.
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.
Now, that doesn't mean you can't do non-dumb things in Java - at Sun Microsystems, we worked on all sorts of very cool R&D-type shit like JavaOS(http://en.wikipedia.org/wiki/JavaOS), Hotjava ( http://en.wikipedia.org/wiki/HotJava), JavaSpaces (http://en.wikipedia.org/wiki/JavaSpaces#JavaSpaces ), JavaCC( http://en.wikipedia.org/wiki/JavaCC ), Jini (http://en.wikipedia.org/wiki/Jini ), ...a very long list of R&D stuff. Sun Research was fucking elite, & staff engineers were considered outright geniuses. None of that cool R&D shit got any traction.
So what got traction ? Whatever yucky shit corporate America wanted - JavaBeans( http://en.wikipedia.org/wiki/Java_Beans ), EJB (http://en.wikipedia.org/wiki/EJB ), Swing (http://en.wikipedia.org/wiki/Swing_(Java) ), various sorts of form-builders, table widgets, reporting shit, IDEs, classfile obfuscators,...
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.
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."
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.
That's an awesome punchline.
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.)
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.
It's like saying C++/Java etc. are confusing because you can only print certain values, but you can't print the print statement.
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?
Like Dijkstra said, getting these high-level concepts in there early is very important.
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.
[1] https://web.archive.org/web/20010429024151/http://www.cs.ute...
[2] http://www.cs.utexas.edu/users/EWD/OtherDocs/To%20the%20Budg...
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.
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.
> 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.
- 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?
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.
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.
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.
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.
Give me a break.
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.
http://homes.cs.washington.edu/~reges/sigcse/basics.pdf
http://homes.cs.washington.edu/~reges/sigcse/basics.ppt
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.)
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.
EDIT: spelling/coherency
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.
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.
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.
Why not a simpler higher-level language as a first language? (pick one, there are lots of simpler languages than Java).
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.
http://channel9.msdn.com/Series/C9-Lectures-Erik-Meijer-Func... (One of the greatest introductions and walkthroughs of Haskell I have ever watched, taught by Erik Meijer)
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)
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.
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.
It was a casual comment in a casual conversation. Apologies if it rubbed you the wrong way; please focus on the well-meant point.
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.)
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 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).
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.
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.)
Me neither, but it is still part of the language and adds a ton of complexity. Which makes the analogy of ocaml to C vs haskell to C++ quite poor.
>The "full" OCaml is pretty complicated
Precisely the point. The full C++ is pretty complicated too. The full haskell is far simpler than either.
>That said, if you're going to use OCaml, you should use the Jane Street libraries
They didn't exist when I used ocaml, and I would never go back to ocaml now.
… following with the NullPointerException in runtime
I've seen plenty of NullPointerExceptions in enterprisey Java to know you generally do get them.
The horror... the horror...
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.
You should try it some day, it is absolutely nothing like your misconceptions.
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.
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".
http://www.haskell.org/pipermail/haskell-cafe/2008-August/04...
I'm genuinely interested in this. Can you link to an article or blog post explaining the problem? Thanks! :)
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.
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.
http://en.wikipedia.org/wiki/File:HintScreenshot.png
1. http://en.wikipedia.org/wiki/Helium_%28Haskell%29 (still alive?)
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.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.
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.
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.
[edit: formatting and typos]
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.
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.
int main(int argc, char **argv)
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.There's no way you can say Haskell is "orders of magnitude better than Java"; maybe it's better, but it's not that much better.
Dijstrka is pretty famous for picking the wrong side of fights about programming languages.
Signed,
Numerous jvm lang and haskell programmer
No. No he did not learn CS from reading Proggit. http://en.wikipedia.org/wiki/Edsger_W._Dijkstra#Life_and_wor...