1. Find your way through the deepest dungeon in the 18th Mini Mapping Contest Poll.
    Dismiss Notice
  2. A brave new world lies beyond the seven seas. Join the 34th Modeling Contest today!
    Dismiss Notice
  3. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
Hive 3 Remoosed BETA - NOW LIVE. Go check it out at BETA Hive Workshop! Post your feedback in this new forum BETA Feedback.
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Structs for Dummies

Discussion in 'JASS/AI Scripts Tutorials' started by Magtheridon96, Jun 15, 2011.

Tags:
  1. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Structs For Dummies


    In this tutorial, I'm going to try to explain the concept of exactly What a struct is and why we use structs.

    Table of Contents

    • What is a struct
    • Why do we use structs
    • Important methods
    • Difference between Static Methods and Methods
    • Struct extends array
    • Struct Variables
    • Thistype Keyword
    • Operators
    • Allocation/Deallocation
    • Modules
    • Initialization
    • Prevent Variable Modification
    • Keyword Keyword
    • Misc Tips

    What is a struct
    I'm going to be as basic as possible:
    • A struct defines a new type
    • A struct can have 8190 instances (Will explain later)
    • A struct can be treated like any other type (
      unit
      ,
      location
      , etc...)
    Just think of structs as virtual objects you can create and destroy.

    Why do we use structs
    Structs make everything easier.
    I'm assuming you're a GUIer. Have you ever created a spell that uses index recycling methods?
    If yes, you'd know how unreadable and ugly index recycling methods are.

    With structs, you can think of spell instances as simple "objects".
    These objects can contain data, and they can manage that data with
    functions known as "methods".

    Important methods
    There are only 5 methods I want you to know:

    The Allocate method is used to allocate an instance:
    Code (vJASS):
    static method allocate takes nothing returns <Name_of_Struct>
        // bla bla bla
        // This method is automatically generated in each struct by JassHelper
        // You just need to call it once inside the "create" method.
    endmethod


    The Create method is like an extension to the allocate method. It calls allocate, then initializes some data.
    You have to create this method yourselves.
    Code (vJASS):
    static method create takes nothing returns <Name_of_struct>
        local <Name_of_Struct> this = <Name_of_Struct>.allocate()
        // do some init stuff
        return this
    endmethod


    The onInit method can be very useful
    I'll explain later
    Code (vJASS):
    static method onInit takes nothing returns nothing
        // anything you put inside here will run at map initialization
    endmethod


    The deallocate method is... I already explained that below :p
    Code (vJASS):
    method deallocate takes nothing returns nothing
        // bla bla bla
        // This method is like allocate, but it deallocates an instance
        // it's automatically generated by JassHelper, so you don't need
        // to write it. Only use it in the "destroy" method
    endmethod


    The destroy method is a must. You should write it yourselves.
    It's like an extension to deallocate. It nulls all the handles in the struct, and deallocates the instance
    Code (vJASS):
    method destroy takes nothing returns nothing
        // null your variables
        call this.deallocate()
    endmethod
     


    These are very basic concepts.
    destroy is always a method
    create is always a static method
    onInit is always a static method

    There's another known method, but please, if you ever see someone use it, you
    should flame them give them a link to this tutorial:

    Code (vJASS):
    method onDestroy takes nothing returns nothing
        // do stuff when you destroy
    endmethod
     


    This method is bad because it generates useless functions.
    Instead of creating this method that runs when you call destroy,
    why don't you just write the destroy method?
    Isn't that logical?

    As you've noticed, there are 2 types of methods: static methods and methods
    If you're curious to know the differences, scroll down.

    Difference between Static methods and Methods
    Static methods and methods have some differences:

    Take the following example:

    Code (vJASS):
    struct Pos
        real x
        real y
        real z
        method moveUnit takes unit u returns nothing
            call SetUnitX(u,this.x)
            call SetUnitY(u,this.y)
            call SetUnitFlyHeight(u,this.z,0)
        endmethod
        static method create takes real X, real Y, real Z returns Pos
            local Pos this = Pos.allocate()
            set this.x = X
            set this.y = Y
            set this.z = Z
            return this
        endmethod
        method destroy takes nothing returns nothing
            // nulling
            call this.deallocate()
        endmethod
    endstruct


    Difference #1:
    The way they're used:
    Code (vJASS):
    function hi takes nothing returns nothing
        local Pos somePos = Pos.create(3,5,2)
        call somePos.moveUnit(GetTriggerUnit())
        call somePos.destroy()
    endfunction


    As you can see, these are the formats:
    Call static method:
    call <NameStruct>.<NameStaticMethod>

    Call methods:
    call <Instance>.<NameMethod>


    These are very simple concepts.

    Difference #2:
    How they work.
    Static methods can be used directly referring to the name of the struct.
    This means that they have to find the instance they are required to work with INSIDE the struct.
    Methods are used referring directly to the instance. This means you don't need to specify the instance since it's already given.

    While working with the instance inside a method, always assume it's called
    this


    Static methods are not required to work with instances. They can just perform
    simple procedures. On the other hand, since methods must take
    instances outside the struct, they are REQUIRED to do something concerning
    that instance.

    Struct extends array
    Here's a simple concept:
    If a struct has no methods, just make it extend an array.
    You can make absolutely ANY struct extend an array, but that would
    require you to implement a dynamic indexing and recycling snippet.

    Example:
    Code (vJASS):
    struct someObj extends array
        static unit u
        static unit v
    endstruct


    Structs that extend arrays are good because normal structs generate lots of trash code.
    A struct that extends an array doesn't have an allocate/deallocate method.

    To learn about writing efficient structs with dynamic indexing and recycling, click here.

    Struct Variables
    There are 2 types of variables in a struct:
    Static variables and normal variables.

    The differences between static variables and normal variables are exactly
    the same as the differences between static methods and normal methods.

    One new and important difference is that static variables are not unique to
    each struct instance. In the following struct:

    Code (vJASS):
    struct bla
        integer i
        static integer j
    endstruct


    Changing the variable j will affect ALL instances of the struct, while changing the variable i will only affect one instance.
    You can think of j as a global that can only be accessed through the struct. (Because it is)
    It isn't associated with any specific instance, but the actual struct itself.

    Thistype keyword
    What?​
    Inside a struct, instead of referring to the name, you could just use the keyword
    thistype
    Why?​
    Because highlighting is awesome :ogre_datass:
    Also, when you read about Modules later in this tutorial, you'll know that using this keyword ​
    is important because you're not always going to know the name of the struct that the module ​
    is going to be implemented into. If you don't get it, then come back to this section after you ​
    finish reading about modules, and I can guarentee that you'll understand it.​



    All of the very basic concepts have been covered.
    If you're not THAT much of a dummy, you may continue to the bottom.




    Operators

    I'm sure you've seen people do something like this:

    Code (vJASS):
    static method operator [] takes <something> returns thistype
        return <Some_data_reffering_to_an_instance_of_the_struct>
    endmethod


    Static method operators have 4 types:

    [] -> Takes a variable inside the brackets
    []= -> Takes a variable inside the brackets and a variable after the "=" sign
    == -> Takes a different instance, and allows you to return a boolean for the evaluation
    < -> Same concept as the above

    Assume the above static method operator is used:
    Code (vJASS):
    function kill takes nothing returns nothing
        local <Name_of_Struct> something = <Name_of_Struct>.allocate()
        call <Name_of_Struct>[GetUnitId(GetTriggerUnit())].killHim()
    endfunction


    GetUnitId is nothing really important for you to know about right now (It's a function in the UnitIndexer library)
    killHim happens to be a method. You may have noticed that we referred to it using the Name of the Struct. This is because the static method
    operator returns an instance of the struct.

    These operators allow us to use not only integers, but units, locations, handles, etc....

    This makes them VERY useful.

    Method operators are the same as static method operators.
    The differences between method operators and static method operators
    are the same as the differences between static methods and methods.

    Here are some examples:

    Code (vJASS):
    struct Unit
        unit u
        method operator hp takes nothing returns real
            return GetWidgetLife(this.u)
        endmethod
        method operator hp= takes real r returns nothing
            call SetWidgetLife(this.u,r)
        endmethod
    endstruct


    You're probably asking this: Why don't we just use variables instead of method operators?

    Keeping a variable like hp inside the struct and constantly updating it is really stupid.
    The method operator allows you to directly return the "GetWidgetLife" native.

    "hp=" is a useful method operator too.

    The above example is basically a simple API (Application Programming Interface)
    Using things like "hp" or "hp=" makes your code look pretty good :p

    Static variables along with static method operators are VERY useful:

    Code (vJASS):
    struct someOtherThing
        unit u
        static integer array index
        static method operator [] takes unit v returns thistype
            return index[GetUnitId(v)]
        endmethod
        static method create takes unit v returns thistype
            local thistype this = thistype.allocate()
            set index[GetUnitId(v)] = this
            set this.u = v
            return this
        endmethod
    endstruct


    Just assume the presence of GetUnitId
    This small template can be very useful when you're referring to instances
    in a struct that are unique to each unit on the map.

    []= is also a very important operator.
    Look at this Unit Data Struct:

    Code (vJASS):
    struct UnitData
        unit u
        integer data
        static integer array index
        static method operator [] takes unit v returns thistype
            return index[GetUnitId(v)].data
        endmethod
        static method operator []= takes unit v, integer i returns nothing
            set thistype[v].data = i // As you can see, thistype[v] returns an instance of the struct :)
        endmethod
        static method create takes unit v returns thistype
            local thistype this = thistype.allocate()
            set index[GetUnitId(u)] = this
            set this.u = v
            set this.data = 0
            return this
        endmethod
    endstruct



    Allocation/Deallocation
    This information can be very useful.
    As I've said before, JassHelper generates 2 methods:
    static method allocate takes nothing returns Name_of_Struct

    and
    method deallocate takes nothing returns nothing


    Sometimes, we want to know if a certain struct instance already exists.
    If yes, most of the time, we wouldn't want to create it again.
    But how can someone detect a null instance?

    Easy: A null struct instance equals 0.

    Consider the following struct:

    Code (vJASS):
    struct Blekh
        static integer array index
        static method operator [] takes unit u returns Blekh
            return index[GetUnitId(u)]
        endmethod
        static method create takes unit u returns Blekh
            local Blekh this = Blekh.allocate()
            set index[GetUnitId(u)] = this
            return this
        endmethod
    endstruct
     


    Assume each unit has a specific instance of this struct.

    In order to check if an instance for that unit exists, we do this:

    Code (vJASS):
    if Blekh[unit] == 0 then // is it null?
        call Blekh.create(unit)
    endif


    Simple, huh?

    You can deallocate instances by setting them to 0, but that's really bad since the instance won't be recycled :)
    Never do that. I repeat, NEVER do that!

    Sometimes, instead of deallocate/allocate, you could create your allocation/deallocation methods :)
    Here's an example: Alloc by Sevion

    Modules
    This concept is very simple:
    A module is just a piece of a struct...
    It can contain methods, static methods and variables.
    Example:
    Code (vJASS):
    private module SomeMod
        unit randomDude
        unit otherRandomDude
        static method onInit takes nothing returns nothing
            set randomDude = ...
            set otherRandomDude = ...
        endmethod
    endmodule
    private struct someThing
        implement SomeMod
        static method create takes unit u, unit v returns <Name_of_Struct>
            local <Name_of_struct> this = <Name_of_struct>.allocate()
            set randomDude = u
            set otherRandomDude = v
            return this
        endmethod
    endstruct
     


    As you can see, modules are 'implemented' into structs.
    You're probably asking yourself: "So?"
    Well, when a module is implemented into a struct, all of it's contents are copied into it.

    Modules have several uses. One very important and common use is Initialization:

    This is the format of Module Initialization.

    Code (vJASS):
    private module Init
        private static method onInit takes nothing returns nothing
            // some Init stuff
        endmethod
    endmodule
    private struct Inits extends array
        implement Init
    endstruct
     


    Initialization
    Take:

    Code (vJASS):
    library temp initializer Init
        private function Init takes nothing returns nothing
            // bla
        endfunction
    endlibrary


    and

    Code (vJASS):
    private module Init
        private static method onInit takes nothing returns nothing
            // some Init stuff
        endmethod
    endmodule
    private struct Inits extends array
        implement Init
    endstruct
     



    What's the difference?
    These 2 initialization methods run in different orders.
    Using the second sample as a template is a requirement if you're initializing important variables because it is executed first.
    In libraries like Ascii, using the second method is important because if the functions included were called
    during map initialization and the library used a common initializer, null values would returned. Anytime you have a library
    that requires you to configure variables like in Ascii, use the second method. The first method can be useful for initialization
    that involves creating a trigger, registering an event, registering a condition, etc...


    Preventing Variable Modification

    If you want to prevent people from modifying variables outside of a given struct, just use the
    readonly
    keyword

    This will prevent variables from being modified OUTSIDE the struct. I repeat, OUTSIDE!!

    Code (vJASS):
    struct HI
        readonly static integer i
        static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
            set thistype.i = 2 // this is ok
            return this
        endmethod
    endstruct

    function hi takes nothing returns nothing
        set HI.i = 4 // This will popup a compile error
    endfunction


    The difference between readonly and private is quite simple:
    -
    readonly
    prevents modification outside the struct
    -
    private
    prevents both modification and access outside the struct

    Keyword Keyword
    Did you know there's actually a
    keyword
    keyword?
    It's important because it allows us to access functions and variables regardless of the position in the library.

    For example:

    Code (vJASS):
    function hi takes nothing returns nothing
        call A.create()
    endfunction

    struct A
        static method create takes nothing returns thistype
            return thistype.allocate()
        endmethod
    endstruct


    This would cause a syntax error since the struct A is positioned below the function.
    But, if we were to do this:

    Code (vJASS):

    private keyword A

    function hi takes nothing returns nothing
        call A.create()
    endfunction

    struct A
        static method create takes nothing returns thistype
            return thistype.allocate()
        endmethod
    endstruct


    Then the syntax error would no longer popup!

    Misc Tips
    • Always destroy struct instances since they're limited
    • Structs can extend other structs, but if you do that, then those structs will share the same instances and thus, you have a greater chance of reaching the 8190 limit
    • If Struct A extends struct B, then struct A will be able to use methods and variables inside struct B (except private ones)
    • Struct instances can be treated EXACTLY like integers
    • Always use
      thistype
      inside a struct instead of the name
    • Timers can only have static method callback functions, making TimerUtils a very useful library. You can use SetTimerData to store the "integer"/"instance" in the timer to load in the static method.
    • Always use module Initializers for standalone libraries with important data.
    • Always use "this" to refer to the instance inside a method
    • Always remember to deallocate instances in your destroy methods.
    • Structs are compiled to arrays. This is why they can only have 8190 instances at once.
    • 0 refers to a null struct instance


    ********************************************

    There are lots of other things for you to know about structs.
    This tutorial only covers the basic concepts. There are other
    tutorials involving structs, but this one is particularly aimed at
    Dummies.

    If you feel that this tutorial isn't sufficient, feel free to post.

    Here's a list of things I'm intending not to cover:
    - Delegates
    - Super
    - Interfaces
     
    Last edited: Mar 21, 2015
  2. Archangel678

    Archangel678

    Joined:
    Apr 25, 2009
    Messages:
    246
    Resources:
    4
    Spells:
    4
    Resources:
    4
    This... helps so much. I must be a dummy, because this clarified so much for me.

    I'd suggest adding a table of contents, so you can reach the differing sections easily.

    This helped me so much... I really hope this gets approved.
     
  3. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Thanks for the positive feedback Archangel ^^
    I'll add a table of contents.

    edit
    Btw, you're not a dummy :D

    edit
    updated
    • Fixed a grammar mistake
    • Added a table of contents

    edit
    updated
    • Moved "Struct Variables" above the "Dummies stop here" indicator :p
    • Fixed Table of Contents
     
    Last edited: Jun 16, 2011
  4. Adiktuz

    Adiktuz

    Joined:
    Oct 16, 2008
    Messages:
    9,674
    Resources:
    23
    Models:
    2
    Packs:
    1
    Maps:
    1
    Spells:
    16
    Tutorials:
    1
    JASS:
    2
    Resources:
    23
    hmmm... more informative than the one I read to learn Structs... ^_^

    Code (vJASS):

    method operator hp= takes real r returns nothing
        return SetWidgetLife(this.u,r)
    endmethod

    //Shouldn't it be like this?

    method operator hp= takes real r returns real
        return SetWidgetLife(this.u,r)
    endmethod
     
     
  5. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Thanks for reporting that error ^^

    fixed it.

    edit
    And yeah, I'm trying to be as informative as possible because these concepts are the ones that nearly
    everyone would fail to easily comprehend when trying to learn structs.

    edit
    update
    Fixed up the design
     
    Last edited: Jun 16, 2011
  6. Jazztastic

    Jazztastic

    Joined:
    Apr 4, 2011
    Messages:
    904
    Resources:
    7
    Spells:
    6
    Tutorials:
    1
    Resources:
    7
    Dunno why, just thought that was funny :)

    I read it, and it would be a nice tutorial if I knew any jass :ogre_hurrhurr:

    But if I am going to learn im definitely going to revisit this tutorial
     
  7. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Thanks ^^
    That really made my day :D

    edit
    update
    I fixed a spelling a mistake :p
     
    Last edited: Jun 17, 2011
  8. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Hmm.. you should cover allocation/deallocation and checking for allocation techniques as well as how custom allocation can avoid trash code generated by vJASS. Put this towards like more advanced techniques.

    Linking to Sevion's Alloc module could be helpful

    Explain why library initializers are horrible. They aren't horrible =P.

    Just cover order of initialization >.>.

    You also forgot to mention readonly and delegates

    And this isn't true
    You also forgot about the like >, +, <, etc operators. Generate an operator vJASS error to get a list of all of the operators.

    That's all for now.
     
  9. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    DUMMIES don't need to know about those =P
    This tutorial covers what a person should know before he starts.
    He'll come across the rest through trial and error.
    I'll add "readonly" though :)

    Thanks for the comments :)
    And btw, ->

    That can be added in by saying: How to detect a null instance: Struct_Instance == 0 -> it is null :p
    I'll link to some resources and improve this tutorial :)


    edit
    Updated
     
    Last edited: Jun 18, 2011
  10. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,430
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Nice tutorial. However, I have a few small comments on certain parts.

    To clarify, the variable j is essentially a global when it has the
    static
    keyword. It isn't associated with any instances (opposed to the variable i), but rather it is associated with the struct itself. (meaning, you have to use
    structName.var
    to access it [at least outside the struct])

    For the keyword
    thistype
    , you may want to mention that it is mostly useful for modules. Since modules are implemented into a struct, and you don't necessarily know the name of the struct that it is being implemented into, you can use the keyword
    thistype
    to refer to the current struct. Although, it is true that it became a habit in normal structs, most likely because of the highlighting. :D

    For modules, you probably want to mention that it will also copy the module's contents into the struct. You jump into talking about how it is used for initialization before saying how to use it in general. ;P

    Well, there is also the keyword
    private
    . You might want to explain the difference between
    private
    and
    readonly
    . (private prevents both access and modification outside the struct, while readonly only prevents modification)

    Otherwise, it seems like a nice tutorial. I like how it is very light, and gives a nice introduction to structs. :) Fix those stuff, and it should be ready for approval. Sorry about the delay.
     
  11. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    exactly ;)

    The spells section has made me strong :p
    I was ready to wait a year for this to be moderated xD

    I'll fix everything up right now :)


    edit
    UPDATED
     
    Last edited: Jun 26, 2011
  12. BBQ

    BBQ

    Joined:
    Jun 7, 2011
    Messages:
    97
    Resources:
    0
    Resources:
    0
    There is no such thing as
    onCreate
    method, so you should remove that.

    You can also mention the use of
    keyword
    for getting library-private struct members.
     
  13. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Really? I always see people using it :L
    Well, If you say so... I'll remove it..

    Yeah, I'll add that in.


    edit

    UPDATED!
     
    Last edited: Jun 27, 2011
  14. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Eh, you forgot to mention the non static special operators

    I think only [] and []= work for non static.
     
  15. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    That's possibly correct :p
    I'll update this tutorial later >_<
    I'm so tired at the moment :p
    Good night ^^
     
  16. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,430
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    afaik all operators work for normal methods. They even use them as non-static method operators in the manual.

    This seems useful enough, so I'll approve it. Sorry for the wait.

    ~Approved.
     
  17. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Updated tutorial and removed something that was causing misconceptions about structs that extend arrays.
     
  18. pred1980

    pred1980

    Joined:
    Mar 19, 2010
    Messages:
    842
    Resources:
    1
    Maps:
    1
    Resources:
    1
    Great Tutorial!!!!
     
  19. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,003
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    I wrote this in 2011.

    It's 2015 and I can't believe some of this bullshit I put together.
     
  20. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    7,014
    Resources:
    12
    Models:
    5
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    12
    You should really rewrite that. There's just a lot of "absolutes" in this tutorial that you should either explain or simply not cover in your tutorial.

    For example, using the onDestroy method over destroy. You describe that as if using onDestroy is ALWAYS dumb, but there is a reason why it exists, which is struct extension. Using onDestroy will work properly on extended structs, whereas overwriting destroy will break inheritance control, unless you implement that manually.

    In fact, you should teach newbies to structs to use onDestroy over destroy, simply because onDestroy universally works, whereas rewriting destroy can break some stuff if you don't know what you're doing.