Wow. It has been way too long since my last post. I feel like a newborn, as a standup comedian at his first important appearance in front of a big crowd having stage freight.
I’ve been working a lot and I put aside my blog, but this is it! The comeback. Haha.
Ok, let’s cut to the chase.
As stated in Part2 of this tutorial, I will talk about inheritance and some more on access specifiers.
We already saw how to create a class, what is a package, class members and methods.. But we also talked about the family of all fruits, how apples are a part of this family, and further more species of apples like Golden Delicious belong to the apples class/family.
So how do we resemble this hierarchy/inheritance (because in it’s essence apples family inherit the attributes of the fruits class, Golden Delicious apples class inherit the attributes of the apples class) in code? This is where inheritance comes in to place. In actionscript only simple inheritance is supported (like in any java like programming languages) as opposed to c++ where multiple inheritance is also available. This makes inheritance very simple and code very easy to understand on one hand, on the other hand though, it can sometimes cause trouble. But we will look into advantages and disadvantages of simple inheritance later on, after we see how exactly is inheritance depicted in code.
Let’s remember our Apple class from the previous part:
package {
public class Apple
{
private var stones
:uint =
4;
public function Apple
() {
trace("A new apple is constructed!");
}
public function getStones
() : uint {
return this.stones
;
}
}
}
Let’s create class GoldenApple that will have as base class the class Apple. For this we have to extend the class Apple. We will use the keyword extends.
So the GoldenApple class will look like this:
package {
public class GoldenApple extends Apple {
public function GoldenApple() {
trace("a new Golden apple is constructed");
}
}
}
That’s it, we have created our class GoldenApple that extends class Apple (or inherits from class Apple, whatever you prefer to say).
We introduced the word base class. This is how a class is called if another class derives (inherits/extends – another term) from it. In our case, Apple is the base class for GoldenApple, and GoldenApple is the derived class.
This now might not look like very helpful, but in fact it is extremely helpful: we can say that an object of the class GoldenApple is of type GoldenApple, but it is also of type Apple! In fact it will have all the functionality of the class Apple, and add it’s own functionality on top of that. This helps with polymorphism, one of the principles of OOP, but we will get to them later in this tutorial. It also helps with code reusing: a trivial example, right from the name of the classes (not a real life use), we say in the class Apple that objects of this class will be apples, we don’t have to say this again in GoldenApple class, because we already know this, since it extends Apple; we only say it’s a Golden one.
Ok. Let’s look at a first example. Let’s create an object of each class and check the output.
var myApple : Apple = new Apple();
trace("myApple stones: ", myApple.getStones());
var myGoldenApple : GoldenApple = new GoldenApple();
trace("myGoldenApple stones: ", myGoldenApple.getStones());
Let’s first notice here that we call getStones methos on myGoldenApple – that’s possible because GoldenApple extends Apple (where getStones method is declared), and the method is declared public. (remember access specifiers from previous part)
The output of this is:
A new apple is constructed!
myApple stones: 4
A new apple is constructed!
A new Golden apple is constructed!
myGoldenApple stones: 4
Let’s now notice the output: the first 2 lines outputted look normal, they are created by the myApple object; we need to pay more attention to the next 3 lines – firstly there is another “A new apple is constructed!” line outputted, although we constructed a GoldenApple object!? – well that is normal, because when the constructor for a derived class is called, this in turn will first call the constructor of the base class; that’s why the first line is “A new apple is contructed!”; after the base class constructor finishes it’s execution, the derived class constructor continues to execute normally, and so it outputs “A new Golden apple is constructed!”; after that the number of stones is outputted as we instructed it to do so with the last trace call.
I should point out that stones member variable is declared private, which means it’s only accessible inside the class Apple, the deriving classes (like GoldenApple) don’t have access to it. Deriving classes can only access public and protected members and methods of the base classes.
As we said in the previous part of this tutorial, internal private public and protected are access specifiers:
- internal – this is the default access specifier for members/methods/namespaces of a class if the access specifier is not specified; this means that the member/method/namespace is accessible anywhere inside the same package as the package the class is defined in
- private – this means that the member/method/namespace is only accessible inside the current class
- protected – the member/method/namespace is accessible inside the current class and by classes the extend this class
- public – the member/method/namespace is accessible is accessible anywhere
Now let’s see another example to better depict these access specifiers:
Let’s say that we’d want to change the value of stones inside GoldenApple class like this:
package {
public class GoldenApple extends Apple {
public function GoldenApple() {
trace("a new Golden apple is constructed");
this.stones = 5;
}
}
}
If we’d try to compile now, the compiler will complain about stones variable being inaccessible inside GoldenApple class. And it is right, because stones is private. So to make it accessible inside GoldenApple, we could make the stones variable internal (this way anything from the global package could access it, probably not what we want), public (anything will be able to access it, again not something that we want here) or protected (only the class that declares it – Apple – and classes the extend this class have access it – GoldenApple; this is what we want).
The new Apple class will look like this:
package {
public class Apple
{
protected var stones
:uint =
4;
public function Apple
() {
trace("A new apple is constructed!");
}
public function getStones
() : uint {
return this.stones
;
}
}
}
Now compilation will run just fine, GoldenApple can set the value of stones to 5. To verify it, try the next example:
var myApple : Apple = new Apple();
trace("myApple stones: ", myApple.getStones()); // this will output 4
var myGoldenApple : Apple = new GoldenApple();
trace("myGoldenApple stones: ", myGoldenApple.getStones()); // this will output 5
Note that “//” in actionscript will depict a line of comment, and everything after // on the same line is treated as such. That means the compiler will ignore what’s on these comments. It’s a good practice to comment out your code, this way you can easily remember later what a piece of code is doing, without having to figure it out from looking at it.
Let’s look at the last example more closely and notice that i’ve set myGoldenApple variable to be of type Apple and assigned to it a GoldenApple object! This is possible and the compiler will be more than happy with it. What makes this possible is that GoldenApple extends Apple and in it’s essence it is an Apple, beside being a GoldenApple also. This is very useful as I said already above and helps us in many ways. For example: we have a list of objects at runtime, we know they all are of some base class type, like Apple, but we don’t know for sure if they are of some inherited class type, like GoldenApple, and so we will treat all the objects as Apple types. Here is an example to clarify this:
var myApple : Apple = new Apple();
trace("myApple stones: ", myApple.getStones()); // this will output 4
myApple = new GoldenApple();
trace("myApple stones: ", myApple.getStones()); // this will output 5
This is the same example as the one above, just modified a bit: in turn of declaring a new variable myGoldenApple : Apple, i’ve used the same already declared variable myApple and assign to it the new GoldenApple object instance. Then the output will be just as above. The ability for something to have many forms, like our myApple variable (at first holds an Apple instance, then holds a GoldenApple instance), is called polymorphism and is one of the principles of OOP: abstraction (data abstraction), encapsulation, polymorphism and inheritance (there are others as well but these are the most important) are the principles of object oriented programming.
Since we’re here at polymorphism, let’s talk a bit about the is operator: this helps us to determine the type of an object at runtime by comparing it to a class type, like this:
var myApple : Apple = new Apple();
if(myApple is Apple) {
trace("an apple");
}
if(myApple is GoldenApple) {
trace("a Golden apple");
}
This code will output “an apple” and exit. However if we were to construct a GoldenApple object instead of an Apple, like this
var myApple : Apple = new GoldenApple();
if(myApple is Apple) {
trace("an apple");
}
if(myApple is GoldenApple) {
trace("a Golden apple");
}
both traces will be executed: “an apple” and “a Golden apple” will both be outputted. That’s because now myApple is an Apple and is also a GoldenApple, so the is operator correctly returns true on both statements.
Polymorphism is used and exemplified very well in serialization/deserialization of objects (actually is used anywhere), and where object factories are used, that’s why in the next part of the tutorial we’ll have an exercise on building serialization/deserialization for our apples.
Now that we have a better grasp of what inheritance is, it’s worth noting that chained inheritance is of course possible. Actually, remember in the first part of the tutorial how we said that any object in actionscript is also of type Object? That’s true. Our apple objects are also Object. That’s because even though we don’t explicitly state that the class Apple extends from Object class, any class will do so automatically. In fact, it is recommended to not explicitly extend the class Object. All the methods and properties of the class Object will automatically be available to your new class.
Because of this possibility of chained inheritance, our GoldenApple class can also be extended by another class, which in turn can also be extended by another class and so on… There’s no limit on the length of this chain.
We said in the beginning that flash supports only simple inheritance and although it makes code much easier to understand, it could also pose serious problems. For this, let’s say that we’d want our GoldenApple to have graphical representation, to be able to add objects of type GoldenApple to the display lists, in essence to became display objects. We know that we can do that only if we use the addChild or addChildAt methods of the DisplayObjectContainer class. But those methods accept parameters of type DisplayObject, which means our class should at least extend the class DisplayObject (in fact we should extend classes that actually have rendering logic, that extend from DisplayObject, like Shape, Sprite, MovieClip…), but unfortunately it doesn’t. What it does, it extends the class Apple. If we don’t extend from Apple anymore and extend Shape, we would end up with a graphical object like we wanted, but we’d loose the methods of the class Apple, and in essence our objects won’t be “apples” any longer, this is not what we want. So here we find ourselves in a bit of trouble. This issue is easily fixed by multiple inheritance, like in c++, where we could extend both classes: Apple and Shape, but unfortunately actionscript doesn’t support it.
So what do we do? We could (and actually this is what it should be done in most situations to avoid these kind of issues) make the class Apple to extend from Shape and GoldenApple extend Apple. This way GoldenApple is an Apple and a Shape (which is a DisplayObject). This is how it’s done in most situations and works perfectly, however it’s not ideal. Why? Let’s think about it for a minute. Apple now is a display object, although Apple is a generic class: it doesn’t know how to draw itself (because it doesn’t know what type of apple it is, it’s size, color, ….) and so it shouldn’t care for being a DisplayObject. But anyway, from a small and simple class Apple, whose objects should be very small, and have a very small memory footprint, it’s now bloated with the intricacies of Shape class even though we don’t need it. And in this case, because we created both Apple and GoldenApple classes and we have access to them, we could change the class Apple to extend Shape, but what if the class Apple was part of a library that we couldn’t modify? What if we later wanted to add interaction capabilities to our GoldenApple class? For that to happen, we’d have to change again the class Apple to extend a class that extends InteractiveObject (like Sprite, MovieClip..), yet another layer of bloating for Apple objects. And what if we wanted later to create another class, RedGalaApple, that extends the class Apple, but we only wanted this class to have visual representation, and not be interactive. We can’t do a thing, the new class will be forced to have interaction capabilities, we would have to switch interaction off by setting mouseEnabled and mouseChildren to false at runtime.
To avoid this bloating of the base class, some use composition patterns, and it is very effective, but we loose the power of inheritance, and the code becomes somewhat awkward. But for devices where we need to squeeze the last bit of memory and power, like mobile devices, this might be the only effective way. I won’t go into detail on how composition looks, but here is a small insight, since we mentioned it: instead of modifying the class Apple, leave it to extend from Object (like completely remove the extends directive); in our class GoldenApple, we add a property visualRepresentation : DisplayObject; we create assign to this property a new Shape and draw whatever we want in it; when it’s time to add our GoldenApple object to the display list, we’ll add the visualRepresentation instead. This is a rough exemplification of how composition works.
Interfaces come to rescue to some degree, implementation of multiple interfaces is allowed. More on interfaces on upcoming parts.
Multiple inheritance would resolve gracefully all these problems, but it will introduce it’s own: the so called Diamond problem – there are 2 classes A and B that extend class C, and you add a class D that extend both A and B: then the C will be duplicated inside D. and others.. Plus the code can be more complicated and more difficult to understand.
About OOP principles, we also mentioned abstraction (data abstraction) and encapsulation so what do they mean?
Abstraction is when you use a class (library), you know it’s public interface and you call it’s public methods/members.. but you don’t really care how is the class built on the inside. You don’t know what the code inside the class actually looks. You make abstraction of what’s on the inside, and only use what’s on the outside, the public interface. The actual logic is “hidden” from you, abstracted.
Encapsulation is the ability to compose an entity from more things. A class is constructed from various member variables, methods, constants… but it represents just one entity. It is said that the class encapsulates all of his properties, methods.. Encapsulation may also refer to the ability to restrict access to part of it’s members, methods, and only allow access to what it wants.
Wow, this is getting really long now and we should end this part here, but before we wrap it up, it makes sense to first talk a little about the keyword final.
We saw how a class can be extended and create derived classes from it. But what if we would want that one class to not be extended, to deny the possibility for another class to inherit from it? Let’s say we built a class and we know that this class shouldn’t ever be inherited from, we want this class to be final. Nothing simpler, just set the final attribute for that class. Example:
package {
public final class GoldenApple extends Apple {
public function GoldenApple() {
trace("a new Golden apple is constructed");
this.stones = 5;
}
}
}
Now the class GoldenApple cannot be extended, it is final, and trying to do so will result in a compiler error.
The keyword final is also available as an attribute for class methods and we will see in the next part how and why is used.
Ok this is the end of this part of the tutorial. I hope you find it useful. As always, comments are more than welcome!
admin Actionscript 3.0, Object Oriented Programming actionscript, as3, as3.0, oop, part 3, part3, tutorial