JASS: Method Interfaces: The Basics & Type IDs

Tutorial By Magentix

0. Index

Foreword
General Agreements
The Interface
[LIST=a]
• Definition
• Example of use: Making a marble roll
• Set up

The Method Interface
[LIST=a]
• Definition
• Example of use: Expanding the marble
• Set up
[/LIST]
Type IDs
[LIST=a]
• Definition
• Example of use: A bag of marbles
• Set up
[/LIST]
Advanced Cases
[/LIST]


1. Foreword
This tutorial is completely in JASS, meaning any GUI user can stop reading here.
Secondly, this tutorial requires you to have a basic knowledge of what structs and methods are.
If you don't know what they are, the advantage of using interfaces probably won't be clear to you anyway.
:)



2. General Agreements
Throughout this tutorial, we will continuously use the same example and expand it to suit our needs.
To keep everything clean and easy to look at, we will put everything in a library.



3. The Interface
a. Definition
A Basic Interface in vJASS is a structure that allows you to refer to multiple related objects as one object-type.
Difficult to understand at first, huh?
No problem, let's just move on to our example.

b. Example of use: Making a marble roll
Suppose we have a nice, round marble.
To describe the marble even more, we create a struct for it that describes the marble's mass, volume, color, etc...

Now, to let that marble roll, we have a function RollMarble that does all the rolling dynamics.

However, since every marble struct will have a different name, we can't write one function that will roll just any marble.
So as you probably already know, we'll have to create a "roll" method in every marble struct.
(The foreword did mention you need a basic knowledge of methods)

Example:
[SPOILER]
[/SPOILER]

Now that we have our methods in every marble struct, we still have one problem:
How do we make different marbles "interact" in a function?

Suppose we want to take two marbles and only roll the heaviest?
This would be impossible since the function RollHeaviest wouldn't know what to require as arguments.
(All marble structs have different names, remember?)

This is where interfaces come in.

c. Set up
As I mentioned above, we need a function to take any two types of marble, and roll only the heaviest.
We can achieve this by giving ALL marbles the same reference name through an interface:


Notice how I used extends Marble on all of our marble structs?
This tells your vJASS compiler (JassHelper) that they can be referred to as "Marble".

However, every method that you use of a Marble inside an external function, must be set in the interface declaration.

In this case you notice that the function RollHeaviest uses the .roll() method and the .weight struct member, but it does not use .color in any way.
Well then, we only have to declare the method "roll" and the real "weight" in the interface, but we're not obliged to declare "color",
since no method or function outside of a specific Marble uses it.

One more thing:
Once you declare a method inside an interface, anything that extends that interface must have it as well!
So not having the method "roll", would make a struct extending Marble cause a syntax error.
Variables, however, can be defaulted inside the interface and any struct that then extends that interface,
will automaticly have that variable declared and defaulted, but may still overwrite it with its own default.

Example:
[SPOILER]
[/SPOILER]

So our previous example would still be valid written like this:




4. The Method Interface
a. Definition
A Method Interface is how I like to call a combination of a Basic Interface with a "parent" struct.

b. Example of use: Expanding the marble
While explaining how and why we should use an interface, I used 2 marbles to show what I meant.
Now suppose we have a few hundred marbles.

All round marbles may have the exact way of rolling (in a straight line for example), but still be different structs because they have a different color, mass, etc.

Having to copy-paste the same "roll" method in every marble of that type, along with all the details would suck, wouldn't it?

This is where Method Interfaces come in handy.

c. Set up


Wow, that's a lot of information!
Let's break it down:

As you can see here, RedMarble no longer extends Marble directly, but uses a small detour over MarbleMethods.
This way, you can default some methods that hardly ever change inside MarbleMethods and still overwrite them if necessary inside a marble struct.
(Just like you can set/overwrite variables in the interface)

Note:
Unlike a struct that is a direct extension of an interface, you may not redeclare variables in a child struct of a Method Interface.
You may still use it and set its value to something else in a constructor, but redeclaring it will cause a syntax error.

Example:
[SPOILER]
[/SPOILER]

To avoid any incidents like this, it is best to always set your child struct's default variables in a constructor method.



5. Type IDs
a. Definition
TypeIDs are the pointers that tell vJASS where to store and find its data for a specific struct type.

b. Example of use: A bag of marbles
So far we learned how to create a standard for objects that allows us to both declare and default variables and methods for all the structs that extend it.
Now we will learn how to add a last, special element: randomness.

Suppose we have a collection of marbles. Let's say a bag of marbles.
Now, having the same marbles over and over again in a specific bag would be boring, wouldn't it?

Well, we are allowed to fill a bag with random marbles now, thanks to TypeIDs!

c. Set up


Wow, another bunch of code!

As you can see, we could create a boring bag of marbles, containing one green, blue and red marble.
Or we could go wild and grab 3 random marbles!

How we achieve this is simple:
We assign an extending struct's typeIDs to a variable by using:
set SomeInteger = STRUCTname.typeid

When we want to use this typeid to create a Marble, we just use:
set SomeStruct = INTERFACEname.create(STRUCTname.typeid)
or, in this case:
set SomeStruct = INTERFACEname.create(SomeInteger)

Well, in this case we have 3 marbles to random from.
So we create an integer array and assign all 3 Marble's typeID to the array.
Instead of just calling <Marble struct name>.create(), we can now call Marble.create(Random value from the TypeID array).



6. Advanced Cases
To finish off, I'd like to point out that you can let your imagination run wild with this "system".

For example, instead of having:
INTERFACE WITH DEFAULT VARS | | V STRUCT WITH DEFAULT METHODS | | V SEVERAL STRUCTS

You could have:

INTERFACE WITH DEFAULT VARS | | | | V V STRUCT A W/ DEF. MET. STRUCT B W/ DEF. MET. | | | | V V SEVERAL STRUCTS W/ MET. SET A SEVERAL STRUCTS W/ MET. SET B

Or, as a "real example":

The Interface Marble, extended by Method interfaces:
- RoundMarble (has the physics for working marbles)
- BrokenMarble (has the physics for broken marbles)

Which are in turn extended by their marble variants




There, I hope this was interesting to read and inspired some people to use interfaces for their next projects :)

Click here to comment on this tutorial.
 
 
Blizzard Entertainment, Inc.
Silkroad Online Forums
Team Griffonrawl Trains Muay Thai and MMA fighters in Ohio.
Apex Steel Pipe - Buys and sells Steel Pipe.