In the last session, you've seen a class hierarchy of overall three classes. The real program of course will contain not three but dozens or hundreds or thousands of classes. So there's a question how to organize them. In this session, we'll learn about packages that can contain classes, as well as how to make classes accessible with imports. We'll find out about this standard Scala library that contains a lot predefined classes already and how these classes are organized in an hierarchy. So generally in Scala as well as in Java, classes and objects are organized in packages. You can place your class or object inside a package simply by adding a package clause like package progfun.example at the beginning of your source file And that would put then every class or object you define later on in that package that you have defined here. And once you've done that, then you can refer to the original object or class, by its so called, fully qualified main. So, the fully qualified name is the name of the package and then a dot and then the name of the object of the class. So, for Hello, it would be progfun.examples.Hello. And, that fully qualified name you can use to refer to Hello from your program or also on the command line when you say, want to run the Hello program you will write scala then progfun.examples.Hello. So let's demonstrate that using the worksheet. What I've done here is I've taken the class rational from the last session which was in worksheet, and I've put this as a standalone class in package week three over here. So now what I want to do is refer to rationals from another worksheet, call it scratch. So what we could do is write new week3.Rational(1, two) and then the worksheet would answer that it's defined a instance of type week3.Rational and the value is one-half. So if it becomes too tedious to write week3.Rational every time you want to refer to a rational, you could also import the rational type from the week three package. The way you do that is with an import clause. You write import week3.Rational. Once you've done that, you can refer to rational without the prefix, because you have imported it previously. Imports come in several forms. This is the most simple one where you import a single named thing. There's also another form of import where you import everything in a given package so the form import week3. would import everything that is defined in package week three It's more general, it's more convenient but sometimes it's less legible because sometimes you really want to have a more precise control over where your names come from. It's also a third form of import which you'll see here in the second line where you can import several names from the same package. So the form import week3, Hell would import both Rational and Hello from the week three package. The first two forms here are called named imports and the last form is called a wildcard import. And another thing to say is that we've seen we can import from packages, but you could in fact import from any object, Any expression that gives you an object and you would simply import all the members of that object. Some entities are imported automatically in any Scala program. These are, all members of packaged Scala. All members of package java.lang and all members of the singleton object scala.Predef. So if you wondered previously for instance how, where did the require or the insert function come from, Well the answer was they were defined in the object scala.Predef, that's an object inside the scaler package and the automatic import of all members of the Predef object made that you could use these names without a further qualification. The same holds for the types Int and Boolean that you've used before so these are actually defined in the Scala package and their fully qualified names are scala.Int and scala.Boolean whereas the name object that we've been using, that actually comes from the Java universe which is in which the Scala universe is embedded. Object is spelled out java.lang.Object. The root object of all Java objects and we have imported that automatically because besides Scala also, all objects in Java land are automatically imported. By now you probably would like to find out more about what classes are there and the Scala library. What can you do with them? What methods do they export? You can do all that using a set of webpage that have been generated by a tool called Scaladoc and you can get that by googling for Scaladoc or by going to this page here which gives you the root package of the scala library and here you can see on the left hand side a set of classes, You can, by displaying all packages you get the set of packages in the Scalar library. If you go through to the packages Scalar then, and I look at a class, let's say Predef object that we've seen here. And you see here an explanation of what's in the Predef object, If we then want to find a method let's say assert in there, then you see here is the definition of the assert methods that are offered by the Predef object. You see here each assert's comes in two versions. One with an error message, one without so that's why I told you the error messages was optional and like that, you can explore, what's out there in the Scala libraries. Now, if you have browsed a little bit this Scala doc, then you probably would have come across set of pages that describe traits, and you might ask well what is a trait? Well in Java, as well as in Scala, a class can only have one super class. You say for this scheme it's a single inheritance language. Single inheritance. And that's actually very constraining because quite often a, a type will have naturally several super types or it would, you would want to inherit behavior from several super entities that all contribute to the final code of the class. To do that, you can use the concept of Traits A Trait is essentially declared like an abstract class. You just use trait instead of the keyword abstract class here. So here for instance we would have a trait of planar objects, where the objects would have a height and width unspecified so those depths don't come within implementation. And then you would have a surface that would be height times width as a default implementation. So that would be a concrete method and those two would be method which would lack an implementation and so are called abstract. So, the idea of traits is then that, claases, objects and other traits can inherit from utmost one class, but they can inherit from arbitrarily many traits. The way you do that, you see here, so here would be a, you would have class square, that extends a shape superclass and then it adds also two traits one is called Planar and one is called Movable. You combine the super class and all the traits you want to inherit with, with here. So with this a combination that adds another trait to some set of classes or traits that you inherit already. In that sense, even though the syntax is different, try traits resemble interfaces in Java. Because in Java as well you can inherit from one class, but multiple interfaces. However, traits actually much more powerful than interfaces in Java because traits can contain fields and concrete methods whereas interfaces can contain only abstract methods. You seen on the last slide, that the trade planner has, had one method surface which already gave a default implementation of the surface property here. That implementation can be overridden in subclasses as always, but if subclasses do not give an implementation, then this one here would be chosen. So there's only one thing you can do with classes, but not with traits. And that is that classes can have value parameters like the numerator and denominator of class rational, Whereas traits cannot. So traits never have parameters. So now let's have a look at the outline of Scala's class hierarchy. So here you see the fundamental Scala classes and the relationship between them. The arrow here means that the class at the root of the arrow is a sub class of the class to which the arrow points. So you see that the classes are organized in a hierarchy. At the top of the hierarchy, you have a class called scala.Any. That's a super class of every other class and Then, you have essentially two set trees of classes. They are rooted in AnyVal and AnyRef So AnyVal is the base class of all so-called value classes and those are essentially the primitive types that you see from, from Java so you have Int and Long, and Float, and Double, and Boolean, and those types would all be subtypes of Scala.AnyVal All the other classes are subtypes of Scala.AnyRef AnyRef itself is just an alias, a different name for Java Lang Object, the root class of all Java classes. And here you see classes like the string class of Java but you also see Scalar classes such as iterabole] and sequence and list. We will get to know them later on. All those classes happen to implement another trait called Scalar.ScalarObject object in addition to the any ref base class. And then on the bottom of the slide, you see two types that are subtypes of many other types. They are called scalar.Nothing and scalar.Now and we'll get to them in the following slides. I should say there's one other twist here in this diagram, we see the relationships between the numeric types, they are actually written with dotted arrows, not hard arrows, and that means that the numeric types, they're not strictly in a subtype relationship with each other, but in a conversion relationship so you can automatically convert and type such as Long to Float, but it's not really a subtype. Why is it not a subtype? Well subtype really means that the conversion is the identity. So that you don't need to rearrange the bits in order to go from one type to the other. Whereas here, definitely if you to go a Long from a Float, you do need to change you representation of that type and what's more in this case here the conversion is not loss free. You might actually lose some precision going to a Long to a Float. Okay now again at the top type in the hierarchy, we have three of them. Any, AnyRef and AnyVal. Any is the base type of all type's and it's also the type that defines certain universal methods. We've already used equality, =,, = and its opposite not equals. Those are actually methods that are conceptually defined in this type any, and those methods actually mapped to the Java equivalence which would be written equals. That's the good method of Java. So =,, = is essentially just a forwarder that cause the Java equals methods unless it's overwritten by a user code. And also, in class, any of you would find the method two string that you've already seen that converts an object to a two string. And finally, you'll have a universal hash code method that produces a hash code from an object. The two subtypes of type Any are the AnyRef which is the base type of also called the reference types and that's an alias of Java Lang Objects and any vowel which is the base type of all value types which for the time being are just the primitive types that Scala inherits from Java. So what about those, those two types at the bottom, Nothing and Null. Nothing is at the very bottom of all Scala types. It's a subtype of every other type. And there's no value that has type Nothing. So you might ask, well, why is that useful. How is the type that has no value useful? Well, there are actually two uses and the two uses, it turns out they're connected. The first is to signal abnormal termination. Sometimes a function would not return but for instance would throw an exception or abort the program and in that case you might ask well what would the return type of that function be? And the answer in fact is the best possible the most precise possible type is Nothing. It doesn't return anything. It will terminate abnormally. And the second usage that you, we are going to see shortly is as an element type of empty collections. So if you have, let's say, a set that contains no elements, You could say it's a set of nothing. Something like that. We will see that in a, in a second later on So speaking of abnormal termination, the usual way that is brought about in both Java and Scala is using an exception and in fact here the syntax for both Scala and Java is exactly the same here we throw expression where you right throw and then comes some exception value and that throw expression would then abort the evaluation of the program with the given exception. Let's do that in an example. Let's say we have a function F def error and it takes a message of type string. And it should give us a throw new error as an exception with the given message. So calling error would immediately abort the program. So what we see here is that the computer type for error was it's a method that takes a string as an argument and it will return nothing. So the, scalatype checker was able to figure out that this expression will not terminate normally and therefore it's [inaudible] type it's nothing. Indeed if we call error now, some exception value than what you would get is not normally termination, but you would get an exception trace that says, well, and the exception Java Lang error was thrown and that was the message that came with it. The other button type we have in the diagram is Scala.Null Turns out that Null is a subtype of all the classes that are, themselves, reference types. And it's also the type of the Null value. Null is written in Scala as in Java. It is a value of every reference type here so, when somebody expects let's say a string you could also pass it now. So, the type of the Null value then is the Null type which is written in the same way just with the capital N and that type is a subtype of every class that inherits from object. On the other hand it's incompatible with subtypes of any value, so let's try that out here, so we could write first val x = null. And here we, worksheet would answer that the value of x is null and the type of excess null with a Null. We can also then assign x to another. Value of, let's say type String And to see that also works so the type... The value of value x, with the type null, That one actually conforms two Strings so you can initialize the value y with the value x. On the other hand what you cannot do is define a value of type Int z and initialize that one to Null. Then you will get an error which says that the. There is a type mismatch the compiler found now. The null value of the null type. And it required an Int. And then there comes a long string that certain implicit conversions are not applicable, which you can ignore. So you've seen that null is a sub type only of the reference types, not of the value types. Lets do an exercise. Let's say I have the following expression. If true one else false. What should the type of that expression be, in your opinion? Possible. So answers would be Int or maybe Boolean, or maybe AnyVal or object or Any. Well, to solve this question the easiest thing would be to just enter this expression in to the web-sheet and see what it says right? So if true, one else false. What do we get? We get AnyVal Why do we get AnyVal? Well Let's look at the two branches of the'if'. The first one is one has definitely type'int'. The second is false and that has definitely type Boolean But then, those two types don't match at this level So what do we do? Let us look back at the arrow key here. So we see that we have Int here and we have Boolean here, but both of these values are also values of the supertype. So that will be either AnyVal or Any. And in this case AnyVal is better. It conveys more information than Any. So the type check actually picked the type that matched both of these values, AnyVal in that case, and that was as specific as possible. So that's why the type checker answered with AnyVal.