- Mar 18, 2012
Today's topic: Extending structs.
These days it appears to be a dying art for vJass resources, hence I want to raise interest on this easily readable way of coding.
So before going into details, let's make sure you have a faint idea what extending structs are.
You're probably aware of
struct A extends array.
The topic for today is
struct A extends B, how it works and how to use it.
I will also talk about finally compiled code when using this feature of vJass.
Quote from JassHelper manualYou base a struct on a previously declared struct, by doing so your new type aquires methods and variable members of the base struct.
Furthermore it is able to use instances of this type with functions and variables of the base type.
Let's quickly repeat allocation and deallocation of structs extending other structs.
For demonstration I will make a realistic spell name: Hydra ( the Diablo II & Diablo III spell )
struct Hydra endstruct
struct FireHydra extends Hydra endstruct
|When using |
|You can use |
If you override
|When destroying a FireHydra instance, Hydra's destructor is called instead and FireHydra's |
|In case you override |
stub methods & super
A method declared in your parent struct can't be re-declared in your child struct. The JassHelper will throw an error:
ErrorMember name already in use by a parent type
stub methodbehaves like a normal
method, but can be overridden in your child struct.
Make use of this feature, if you want different method behaviours in your child struct than in your parent struct. ( i.e. a filter )
superforces the parent method to be called, you might need this when extending an interface or avoiding an overrriden
I guess the usage of
superis very seldom to non-existent.
An example is better than 1000 words:
// In the example Hydra is our parent struct. struct Hydra stub method onCreate takes unit new returns nothing endmethod stub method onFilter takes unit filterUnit returns boolean return true endmethod // Child structs can use methods of parent structs. method fire takes unit target returns nothing endmethod endstruct // In the example FireHydra is a child struct extending Hydra. struct FireHydra extends Hydra // overrrides stub method onCreate. method onCreate takes unit new returns nothing call BJDebugMsg("parent onCreate overridden") call super.onCreate(new)// Will now also call the parent struct onCreate method. endmethod // overrides stub method onFilter. Returned boolean may now also be false. method onFilter takes unit filterUnit returns boolean return UnitAlive(filterUnit) endmethod // Will throw an error, because method fire is already declared in Hydra! method fire takes unit target returns nothing endmethod endstruct
LimitationIt is impossible to call a stub method within the parent creator
library A struct A // Eval via call TriggerEvaluate(st__A_onCreate[si__A_type[this]]) public stub method onCreate takes nothing returns nothing // Will always run endmethod static method create takes nothing returns thistype local thistype this = thistype.allocate()// set si__A_type[this]=1 call this.onCreate()// Evaluates st__A_onCreate[si__A_type[this]]! return this// Returned to a function, which set si__A_type[this]=2 endmethod endstruct struct B extends A private method onCreate takes nothing returns nothing // Will never run endmethod static method doit takes nothing returns nothing local B this = B.create()// here si__A_type[this]=2 call Print(I2S(this.getType()))// Prints 2 endmethod endstruct endlibrary
One could think: Quite awesome this vJass!
But it is very important to analyse the code generated behind stub method and extending structs.
Constructor and destructors stay as described above, but how is it possible to "override" stub methods?
|Stub methods create a |
Variables of the same type are shared across structs in your map to reduce overall used globals to a minimum.
These variables are required to pass over agruments when using trigger evaluations.
overridden stub methods
|Once re-declared in your child struct, stub methods are accessed via |
So we have an additional
Structs extending array ( i.e.
struct Hydra extends array) are not discussed in detail in this tutorial.
What you should know is that array structs do not generate a struct creator and destructor. You have to do all of this by yourself.
You want to use array structs for the . syntax and for struct fields. ( JassHelper link )
struct extends arrayis also recommended for large scale systems,
as high frequency trigger evaluations ( onDestroy, stub methods, ... ) can have a negative impact on the overall computation time.
typeid & getType()
Let's imagine you want to code more different Hydra type spells in your map ( i.e. Ice, Lightning, Venom-Hydra ... ).
How is it possible to distinguish which type of Hydra an instance is? Remember they are all allocated via our parent struct: Hydra.
|Each struct has an id represented as |
You can read the struct id by using struct.typeid ( i.e.
These fields allow the following comparison:
Many people postulate that extending structs should be avoided due to extra code generation and trigger evaluations.
We can't deny that stub methods are not top performers in vJass coding ( due to trigger evaluations ),
however the syntax is very readable and easy to use. Performance-wise you will not realise a difference ingame in 99% of all cases.
As an example extending structs are beneficial when it comes to coding spell resources for you map. ( reconsider my Hydra example )
Alternative ways of coding ( eventually faster ) with modules combined with static ifs and Events are often really hard to understand at a glance.
I totally recommend to try out extending structs for clean, readable OOP coding in vJass.
Some links to resources on THW using the features discussed above:
Thank you for your attention.
Last edited by a moderator: