Extender Methods mean Polymorphism!

From Adventure Game Studio | Wiki
Revision as of 16:29, 19 September 2009 by *>Monkey 05 06 (New page: So you think AGS doesn't support polymorphism? Well up until AGS 3.0 that would be a correct assumption. Okay we may be getting a tad bit ahead of ourselves here. Just what is this "polymo...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

So you think AGS doesn't support polymorphism? Well up until AGS 3.0 that would be a correct assumption. Okay we may be getting a tad bit ahead of ourselves here. Just what is this "polymorphism" anyway?

Polymorphism is a concept specifically dealing with data structures (structs in AGS), inheritance, overloading, and other concepts which may seem largely foreign.

Inheritance

Inheritance is the idea that we're going to define a struct that inherits functions and properties from another type. For an example of this we can look at AGS's built-in GUI control types. Each of these types derive functions and properties from the base GUIControl type.

For example if we had a struct defined such as:

 struct a {
   int ia;
 };

We could then derive a new type from our struct a by doing this:

 struct b extends a {
   int ib;
 };

Although struct b only defines the property ib it will also have the property ia which is inherited by the extends keyword. This is where properties such as Label.X and Button.Width come from; they are inherited from the GUIControl type.

Overloading

The idea of overloading is that you're going to have two (or more) functions with the same name. So how then do you know which version of the function is going to get called? Well, this can be determined by a number of factors but AGS makes it easy. In AGS you can only overload a function via an extender method.

You can't define two extenders for the same struct with the same name. However what you can do is define two extenders with the same name for two different structs. So you could implement a Fade function for both the Character and Object types. Both functions are called Fade, but AGS would know which one you're calling just by how you call it. So if you put cEgo.Fade it would know to call the Character function, and oKey.Fade would call the Object function.

Polymorphism

Now that we understand inheritance and overloading we can start to understand the idea of polymorphism. Going back to the GUIControl type we already know that several derived types (Button, Label, etc.) inherit from this type. So if we define an extender method on the GUIControl type that method will be inherited to each of the derived types! (NOTE: As of this writing, 19 September 2009, autocomplete will not detect inherited extender methods. They can be called, but be warned they won't appear in autocomplete.)

The idea of polymorphism is that you want to let one of the derived types overload the inherited member so it will act differently.

Say for example you wanted the Label type to act differently when you call your extender (defined on the GUIControl type) than it does when it's called on a GUIControl object or any of the other derived types. Lucky for you AGS actually allows this behavior. All you have to do is define an extender for the Label type with the same name and it will override the inherited extender.

So we could see this in action with this crappy example!

 // header file
 import function DoSomething(this GUIControl*);
 import function DoSomething(this Label*);
 
 // script file
 function DoSomething(this GUIControl*) {
   Display("GUIControl.DoSomething called!");
   // do something with a GUIControl or derived type
 }
 
 function DoSomething(this Label*) {
   Display("Label.DoSomething called!");
   // do something with a Label
 }
 // wherever
 GUIControl *gcat = GUIControl.GetAtScreenXY(mouse.x, mouse.y);
 gcat.DoSomething();
 btnButton.DoSomething(); // NOTE: though valid does not autocomplete
 sldSlider.DoSomething(); // NOTE: though valid does not autocomplete
 invInvWindow.DoSomething(); //  // NOTE: though valid does not autocomplete
 lblLabel.DoSomething();

We would get the output from this:

 GUIControl.DoSomething called!
 GUIControl.DoSomething called!
 GUIControl.DoSomething called!
 GUIControl.DoSomething called!
 Label.DoSomething called!

The first call is directly on a GUIControl object so it calls GUIControl.DoSomething as you'd expect. The next three are on derived types of the GUIControl type (with no overloaded extender defined) so they also call the GUIControl.DoSomething method. The final call is on a Label object which does have an overloaded extender defined, so only the overloaded extender, Label.DoSomething, gets called.

The extender on the Label type completely overrides the GUIControl type's extender method. You can overload as many derived types as you want (even overloading them all if you wish!) but for those types that aren't overloaded the base type's extender method will be called instead. This is precisely what polymorphism is, and that's how you do it in AGS (not a particularly useful example mind you, though it should get the idea across).


NOTE: In order for polymorphism to be applied in AGS all of the functions you want to overload must be declared as extender methods. If the method is not defined as an extender then it cannot be overloaded. That means you cannot overload any of the built-in functions. The base definition and any overload definitions must be extenders for this to work!