[As described below, this is Part B of a 3-part course. Participants should complete Part A first -- Part B "dives right in" and refers often to material from Part A.]
This course is an introduction to the basic concepts of programming languages, with a strong emphasis on functional programming. The course uses the languages ML, Racket, and Ruby as vehicles for teaching the concepts, but the real intent is to teach enough about how any language “fits together” to make you more effective programming in any language -- and in learning new ones.
This course is neither particularly theoretical nor just about programming specifics -- it will give you a framework for understanding how to use language constructs effectively and how to design correct and elegant programs. By using different languages, you will learn to think more deeply than in terms of the particular syntax of one language. The emphasis on functional programming is essential for learning how to write robust, reusable, composable, and elegant programs. Indeed, many of the most important ideas in modern languages have their roots in functional programming. Get ready to learn a fresh and beautiful way to look at software and how to have fun building it.
The course assumes some prior experience with programming, as described in more detail in the first module of Part A. Part B assumes successful completion of Part A.
The course is divided into three Coursera courses: Part A, Part B, and Part C. As explained in more detail in the first module of Part A, the overall course is a substantial amount of challenging material, so the three-part format provides two intermediate milestones and opportunities for a pause before continuing. The three parts are designed to be completed in order and set up to motivate you to continue through to the end of Part C.
Week 1 of Part A has a more detailed list of topics for all three parts of the course, but it is expected that most course participants will not (yet!) know what all these topics mean.

Reviews

KR

I'm a pretty experienced C/C++ programmer and this course has been a brilliant introduction into functional programming and the underlying philosophies underpinning programming languages in general.

JM

May 09, 2018

Filled StarFilled StarFilled StarFilled StarFilled Star

DO THIS COURSE. It brings together everything in part A. In particular, the final shorter week on the differences between Statically and dynamically typed languages is mind-bending and brilliant.

From the lesson

Section 7 Including a Quiz

In the last module of Part B we will use our experience programming in ML and Racket to
compare and contrast static typing and dynamic typing. This is not only the most important difference between these two languages, but it is a fundamental topic in the study of programming languages. Learning it can help you program more effectively in both kinds of languages. After completing this week's quiz, don't forget to watch the Part B Wrap-Up and Part C Preview video.

Taught By

Dan Grossman

Professor

Transcript

[MUSIC] In this segment I want to briefly talk about weak typing, which is actually a separate topic from static versus dynamic typing. But because it's often confused with that issue, I thought it would be good to put it here in the course and sort of set the record straight. So weak typing, which is probably best known as the sort of type system that C and C++ have is what I'll describe as follows. There exist programs that, according to the language definition, must pass static checking but then when the program is run they're allowed to do absolutely anything. I like to say that they're allowed to set the computer on fire by which I mean they're allowed to crash, they're allowed to corrupt your data, they're allowed to be a virus, they're allowed to delete all your files and so on. So the idea is there are programs that perform operations that don't make any sense but the dynamic checking that would catch those errors before they do anything disastrous is optional. And in practice and implementations of C and C++ is not done. Now if you only have a program than Racket or Python or ML or Java, this would seem crazy. Why would you allow a language implementation not to do these checks? And the answers are numerous. So it turns out there are good reasons to use C or C++ in some settings. One is that it makes the language easier to implement for all sorts of different computing platforms. The checks are left to the programmer. Now I would prefer to have a harder language implementation and make programming easier, but that's not always the tradeoff that people make. Probably the biggest one that people emphasize is performance. That if you don't have to perform dynamic checks, then not only do you save the time of not doing them but you don't have to use space in your program to store the various tags and sizes and other things that you need in order to do the dynamic checks. And that's actually related to this third reason which is just lower level. That if you want a language where programmers can control things like the representation of data, then you can't have dynamic checks that require extra fields that the programmer doesn't have control over. But that's really about C and C++ which this course is really not about. I just want to emphasise the idea of weak typing and to tell you it's not a very good name, right? It doesn't really have to do with type systems, it has to do with there being things that you're trying to prevent, some bad property x and not checking for it. You're not checking for it statically and you're not checking for it dynamically and you're saying if it happens, the computer is allowed to catch fire. So you can see it's not really about typing when you realize that one of the biggest reasons that C and C++ programs do unexplained things, up to and perhaps not including setting the computer on fire, is when you have array bounds violations. Which are not checked, but most people don't think of array bounds as related to the type system in these languages. So it turns out that decades ago people used to be fans of weak typing, some people were, many people were not. And the people in favor of weak typing had this saying, strong types for weak minds. So the idea is that you would only want to have strong typing, which is the opposite of weak typing if you thought that computers are smarter than humans. And we know they're not. We know that static checking would never be perfect. So you always need these smart humans to have some work around to turn off the checking that they may know is unnecessary and the computer is not smart enough to realize is unnecessary. That in the end, languages should not get in the way of humans and humans should be able to say, trust me. I say this is right and if I'm wrong, you can do anything. And I think the conventional wisdom has really changed on this quite a bit. That in reality, we've learned that humans are really bad at avoiding bugs and we need all the help we can get. And if we can write a computer program that does some of the checking for us, it's a nice division of responsibility. The person writing the static checker or dynamic checker can focus on getting just the checking right. People writing applications can focus on the logic of their applications and rely on the automatic checking that we get in strongly typed programming languages. It's also fair to point out that conventional wisdom has changed because our type systems have just gotten a lot better. They're more flexible, we have things like polymorphism, we have things like subtyping that have made it a lot easier to program in a language with a strong type system and not feel like its getting in your way. The weak typing argument in my mind really breaks down when you look at the Modern size and complexity of software. There are operating systems today that literally contain 30 or 40 or 50 million lines of C code. If you're riding 200 or 1,000 lines of C code I'm sympathetic to the argument that humans can look at that code and through hard work and starring carefully, get most of or even all the bugs out of it and maybe a type system shouldn't tell them that it knows better. But when you get to 30 million lines, and any one line in that program could cause the entire application to perform arbitrary behavior I just think it's ridiculous to expect that we don't want some assurance that certain kinds of errors and preventable properties are not possible in the software. I like to joke when I'm teaching this stuff that there was an important bug related to the weak typing of C announced just this week. And I actually don't have to look that up because there are plenty of websites that catalog these things, and I'm sure there's something posted on them every week. So we just have too much software, too complex of software in the world today to sort of rely on humans to get their software right. The thing I want to emphasize though, is that Racket is not weakly typed. This is just a matter of definitions. Racket is dynamically typed. It checks a lot of things like not using a number as a procedure at run time. But that is very different than not checking them. What we have is a language definition that says those errors will be detected at particular points, and an error will be raised. Then in the language implementation, the checks can be removed if the implementation can perform some analysis to show that they would never fail. So, the language definition says these checks have to be in there. If the check would ever fail, that has to be indicated by an exception or an error in the program. But you can remove checks in the implementation if you're sure they would never fail. And this is all very different than the sort of catch fire semantics we've been talking about with C and C++. And just to finish up this segment let me talk about another topic that is not weak typing and is not dynamic typing but is often confused with these things. And that's this issue of what primitives can, sorry, what operations can primitives do? So in some languages, if you try to call plus with strings, you get an error. That's a type error in ML, it's a run time error in Racket. But in other languages, plus just means string concatenation. But maybe in those languages trying to add a string and a number is an error. And then their language is where it's not an error where it will convert a number to a string and you end up with a four characters string like foo3. There other things that I'm used to being errors and some languages say or not. If I access the 10th element of an array and that only has five elements is that an error? Well, in some languages it says no, you'll just get something like no back. You'll get an empty list back, or something like that. Even if you assign to an array, what if we just made an array bigger? Suppose you had a function, like in Racket, you called it with the wrong number of arguments. That's an error in Racket, but a different language could make a different choice. It could say, if you pass too many arguments, we'll just ignore the extra ones. Maybe if you pass to few arguments. We'll pass in 79 for all the arguments you were missing. You can define your language in these ways to be more flexible and decide that fewer things are errors. But this is not actually static versus dynamic checking. We sometimes think of languages that are more permissive on these things as being more dynamic. But technically that's not what they are. All that's going on is that we have changed the evaluation rules for a primitive in our language. Whether it's accessing an array, calling a function or performing an addition. And if you change the evaluation rules for your language to allow more arguments and more types of things. You are being more flexible. You are increasing the set of legal programs at the expense oftentimes of detecting bugs in a timely fashion. That instead, you just silently continue, even if its unlikely that that's what the programmer meant. So some of the tradeoffs between static checking which catches bugs earlier and dynamic checking which catches them later, apply here. Here we're being even more dynamic and being even more delayed in announcing that something seems to have gone wrong but it's not really static checking at all. It's not really dynamic checking. It's just saying that I've changed the evaluation rules of my language.

Explore our Catalog

Join for free and get personalized recommendations, updates and offers.