[As described below, this is Part C of a 3-part course. Participants should complete Parts A and B first -- Part C "dives right in" and refers often to material from Part A and Part B.]
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.

Рецензии

NV

One of the best courses of my career. This was truly programming languages. You'll look at your programs, in any language you use, in a whole different way! Highly recommended!

HB

Feb 08, 2018

Filled StarFilled StarFilled StarFilled StarFilled Star

A course with a lot of work, but great reward. Dan who holds the course is passionate and knows what he talks about, making it a pleasure to listen to.

Из урока

Section 8 and Homework 6 (First Module with Ruby)

Let's get started programming with Ruby, including learning about Ruby's variant of (almost) function closures and the "inheritance and overriding" that is the essence of object-oriented programming. The welcome message has a few additional comments about "what makes Ruby different" and how to approach the (rather different) homework assignment, so let's get started...

Преподаватели

Dan Grossman

Professor

Текст видео

[MUSIC] Any study of object programming in a dynamically typed language would not be complete without studying the topic of what has become known as duck typing. So first, let me explain the name. There's this funny expression in English that if it walks like a duck and it quacks like a duck, it's a duck. A more precise saying would say if it quacks like a duck and walks like a duck, it's not relevant for our present purposes that it may not actually be a duck. So that's the idea. And in programming what comes up is when you're writing some method, you might be thinking, I need to take in an instance of some class Foo. But really, all you're doing is taking in some argument and calling methods on it. And if there's something out there that walks like a Foo and quacks like a Foo but it's not actually an instance of Foo, then in a dynamically type language, your code might still work and it might be appropriate for clients to pass something that is not actually a Foo. So when you embrace duck typing like this, you really stick with not assuming anything about objects, except that they have certain methods, and you can call them with certain arguments, and you avoid language features, which Ruby does have for things like testing, are you actually a Foo? What is your class? Are you an instance of a particular class? So people generally argue that by embracing duck typing, you get more code reuse. And you get more code reuse because you're taking a very OOP approach that the only thing you care about an object is what messages you can send it. Now, the minus of this is that it makes almost no code equivalent. It makes it impossible to replace one set of method calls with a different one because then things that used to look like a duck, don't look like a duck anymore. That for numbers x+x and x*2 are equivalent in Ruby. But, if people are passing in things that are not numbers, and that handle x+x and x*2 in different ways, then making this sort of change is going to have undefined or confusing behavior. So colors in a duck typing world can end up assuming too much about how a method is implemented. And you'll end up losing all the obstraction advantages that are so important in that program. So, let me show an example of this, just here on the slide. Suppose there was some class out there for points in the plane, so they had an x coordinate and a y coordinate. And suppose we wanted to be able to mirror a point, so we want to update a point to change its x coordinate to its negation while leaving its y coordinate alone. This is what happens when you look in a mirror, if you will. And OOP style would actually make a mirror update method be a method of the point class. But for sake of example, suppose instead I just have this helper method that takes in a point and changes it so it's pt.x=pt.x* (-1), that's the idea. So, the natural thought is the look up this code and say, well, it takes a point object and negated the x value, updating it in place. But that's not actually what this does. A slightly closer look at it would say well, it takes anything that has getter and setter methods for @x instance variable and then replaces @x with @x*(-1), right? So if I add something that was not an instance of point but had these getter and setter methods, then this code would presumably do something useful on such an object. Now, hopefully at least some of you are saying but wait there, that's still too restrictive. You're assuming that the getter and setter methods are actually updating an @x instance variable and that's part of the object implementation that's none of our business as the writers of mirror update. So a more precise description yet would say that mirror update can take anything with methods x= and x and what it does is it calls the x= method with the result of multiplying the result of calling the x method by -1. Whether these things are accessing an instance variable, whether the x= method even updates anything, it would be poor style to have a method called x= that didn't actually update something but nothing would stop you. And if you have any such object, you can pass it to mirror update and something presumably useful will happen. And just to finish this story, this is still not quite correct because you're assuming in this description that the * method is actually performing multiplication. There's no reason that needs to be the case. I would say that the true duck typing interpretation of this code is it takes anything with the method x= and a method x where the result of calling the x method, where we say pt.x, is an object that has a * method, that can take -1. And then, what this method does is it sends the result of calling x the * message -1 and sends that result to the x= message. That is duck typing. It's often convenient, what I don't like about it is now our documentation for the method is essentially the entire body of the method. We've hidden absolutely nothing from clients. We've told them exactly what we're going to do so they could have just used the code themselves rather than relying on our method. So the plus of this is that maybe mirror update is now useful for classes we did not anticipate. That by writing the code without checking that we take an instance of point, other clients can reuse our code in ways that may be useful to them. But the minus, is that if someone does reuse our code with an instance of an object that relies on things like they're being at * message or x= being a setter or whatnot, then we can't replaced code like pt.x * (-1) with something like -pt.x. This works if we know we have a point that returns a number, because we know negation and multiplying by -1 is the same on numbers but that's assuming things that duck typing does not get to a assume. So, for examples like this, like mirror_update, I think duck typing is actually often poor style. That there may be things that are not quite points that are appropriate to pass mirror-update, but I wouldn't want to pass some arbitrary thing that just happens to have methods x and x=. But there are good examples of duck typing, I have to admit. If you take simple helper functions, admittedly, this is a little too simple to be compelling like something that doubles its argument by calling x+x, it's rather nice that given this I could pass in a number because those things have plus messages. I could pass in a string, and then I would concatenate a string with itself or I can even take my own code like the MyRational objects, I define in earlier segments. And because I define plus, I could then pass those objects to these double function and have them get doubled, even if the original writer of this code was thinking numbers, or was thinking I can support anything that has a plus message. And that's sort of the pluses and in my opinion minuses of duck typing and how it's relevant to object programming in a dynamically typed linkage.