[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 absoultely 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 implementation of C and C++ is not done. Now, if you've only ever programmed in 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 make 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 trade-off that people make. Probably the biggest one that people emphasize is performance, that if you don't have to perform dynamic checks That 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 to language for a programmers can control things like the representation of data, then you can type dynamic checks that requires extra fields that the programmer doesn't have control over. But that's really about C and C++ which is pa course is really not about. I just want to emphasize the idea of weak typing and to tell you that its not a very good name, right it doesn't really have to do. With type systems. It has to be 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 the computers were smarter than humans. And we know they're not, we know that static checking would never be perfect. So you always need the smart humans to have some work around, who's 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 type of 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 made it a lot easier to program in a language with a strong type system. And not feel like it's 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 writing 200 or 1000 lines of C code, I'm sympathetic to the argument that humans can look at that code and through hard work and staring carefully get most of or even all of 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 of 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 and now it's 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 is something posted on them every week. So, you know, 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. This is 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 primatives 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 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 there are languages where it's not an error. Where it will convert the number to a string and you'll end up with a 4 character string like foo 3. There are other things that I'm using to being errors. And some languages say are not. If I access the 10th element of an array and that array 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 of 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 arguments. That's an error in Racket. But a different language can make a different choice. It could say, if you pass too many arguments, we'll just ignore the extra ones. Maybe if you pass too 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 beside 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 its accessing an array. Calling a function or performing an addition. And if you change the evaluation rules for your language, to allow more arguments, more types of things, you are being more flexible. You're increasing the set of legal programs. At the expense, often times, of detecting bugs in a timely fashion. Than, instead, you just silently continue, even if it's unlikely that that's what the programmer meant. So, some of the trade offs 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.