1. The poll for our 11th Music Contest is up! Help us choose the most awesome cinematic tracks by casting a vote!
    Dismiss Notice
  2. Melee Mapping contest #3 - Poll is up! Vote for the best 4v4 melee maps!
    Dismiss Notice
  3. The 30th edition of the Modeling Contest is finally up! The Portable Buildings need your attention, so come along and have a blast!
    Dismiss Notice
  4. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice

Issues with structs in vJass

Discussion in 'The Lab' started by Prometheus3375, Sep 2, 2018.

  1. Prometheus3375

    Prometheus3375

    Joined:
    Jul 20, 2018
    Messages:
    31
    Resources:
    0
    Resources:
    0
    Before writing it I have googled this topic, but found nothing. Here I describe some bugs in vJass connected with structs. I used JassHelper 0.A.2.B from NewGen pack.


    First issue. Lets consider next code.
    Code (vJASS):
    struct A[8191]
    endstruct

    There is generated code below.
    Code (vJASS):
    globals
    //JASSHelper struct globals:
    constant integer si__A=1
    integer si__A_F=0
    integer si__A_I=0
    integer array si__A_V
    integer array si__A_2V

    endglobals


    //Generated allocator of A
    function s__A__allocate takes nothing returns integer
     local integer this=si__A_F
        if (this!=0) then
                set si__A_F=si__A_V[this]
        else
            set si__A_I=si__A_I+1
            set this=si__A_I
        endif
        if (this>8191) then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Unable to allocate id for an object of type: A")
            return 0
        endif

            set si__A_V[this]=-1
     return this
    endfunction

    //Generated destructor of A
    function s__A_deallocate takes integer this returns nothing
     local integer used
        if this==null then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: A")
            return
        else
                set used=si__A_V[this]
            if (used!=-1) then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: A")
                return
            endif
        endif
            set si__A_V[this]=si__A_F
        set si__A_F=this
    endfunction

    You may notice that
    integer array si__A_2V
    is redundant.
    The same issue takes place if I put any multiplier of 8191. For example, for 16382
    integer array si__A_3V
    is declared which is never used. If I put 16383, this array will be used, but 16383 indexes can be described with two arrays since 16383 = 8192 * 2 - 1 (-1 for null struct). This is true for any integer in range (8191 * k, 8192 * k - 1], where k > 1.


    Second issue is more important.
    Here is code.
    Code (vJASS):
    struct A[16382]
    endstruct

    struct B extends A
    endstruct

    struct C extends B
    endstruct

    If you compile it, next message will be thrown.
    [​IMG]

    For some reason JassHelper forgets to generate some variables. OK, let's do it by our own.
    Code (vJASS):
    globals
        integer array si__B_type
        integer array si__B_2type
    endglobals

    After compilation next code will be generated.
    Code (vJASS):
    globals
        // Generated
    integer array si__B_type
    integer array si__B_2type


    //JASSHelper struct globals:
    constant integer si__A=1
    integer si__A_F=0
    integer si__A_I=0
    integer array si__A_V
    integer array si__A_2V
    integer array si__A_3V
    constant integer si__B=2
    constant integer si__C=3
    integer array si__A_type
    integer array si__A_2type
    integer array si__A_3type
    trigger array st__A_onDestroy
    integer f__arg_this

    endglobals


    function si__A_getType takes integer this returns integer
        if(this<8191) then
            return si__A_type[this]
        else
            return si__A_2type[this-8191]
        endif
    endfunction

    function si__B_getType takes integer this returns integer
        if(this<8191) then
            return si__B_type[this]
        else
            return si__B_2type[this-8191]
        endif
    endfunction

    //Generated allocator of A
    function s__A__allocate takes nothing returns integer
     local integer this=si__A_F
        if (this!=0) then
            if(this<8191) then
                set si__A_F=si__A_V[this]
            else
                set si__A_F=si__A_2V[this-8191]
            endif
        else
            set si__A_I=si__A_I+1
            set this=si__A_I
        endif
        if (this>16382) then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Unable to allocate id for an object of type: A")
            return 0
        endif

        if(this<8191) then
            set si__A_type[this]=1
        else
            set si__A_2type[this-8191]=1
        endif
        if(this<8191) then
            set si__A_V[this]=-1
        else
            set si__A_2V[this-8191]=-1
        endif
     return this
    endfunction

    //Generated destructor of A
    function sc__A_deallocate takes integer this returns nothing
     local integer used
        if this==null then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: A")
            return
        else
            if(this<8191) then
                set used=si__A_V[this]
            else
                set used=si__A_2V[this-8191]
            endif
            if (used!=-1) then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: A")
                return
            endif
        endif
        set f__arg_this=this
        if(this<8191) then
            call TriggerEvaluate(st__A_onDestroy[si__A_type[this]])
        else
            call TriggerEvaluate(st__A_onDestroy[si__A_2type[this-8191]])
        endif
        if(this<8191) then
            set si__A_V[this]=si__A_F
        else
            set si__A_2V[this-8191]=si__A_F
        endif
        set si__A_F=this
    endfunction

    //Generated allocator of B
    function s__B__allocate takes nothing returns integer
     local integer this=s__A__allocate()
     local integer kthis
        if(this==0) then
            return 0
        endif
        if(this<8191) then
            set si__A_type[this]=2
        else
            set si__A_2type[this-8191]=2
        endif
        set kthis=this

     return this
    endfunction


    //Generated allocator of C
    function s__C__allocate takes nothing returns integer
     local integer this=s__B__allocate()
     local integer kthis
        if(this==0) then
            return 0
        endif
        if(this<8191) then
            set si__A_type[this]=3
        else
            set si__A_2type[this-8191]=3
        endif
        set kthis=this

     return this
    endfunction

    JassHelper sees that B is a parent of C and generates function
    si__B_getType
    , but this function is useless as C is a descendant of A and uses
    integer array si__A_V
    .
    This would not be so weird unless next case.


    Third issue is here.
    Code (vJASS):
    struct A[16382]
        stub method someMethod takes nothing returns integer
            return 1
        endmethod
    endstruct

    struct B extends A
        stub method someMethod takes nothing returns integer
            return 2
        endmethod
    endstruct

    struct C extends B
        method someMethod takes nothing returns integer
            return 3
        endmethod
    endstruct

    globals
        integer array si__B_type
        integer array si__B_2type
    endglobals

    Code (vJASS):
    globals
        // Generated
    integer array si__B_type
    integer array si__B_2type


    //JASSHelper struct globals:
    constant integer si__A=1
    integer si__A_F=0
    integer si__A_I=0
    integer array si__A_V
    integer array si__A_2V
    integer array si__A_3V
    constant integer si__B=2
    constant integer si__C=3
    trigger array st__A_someMethod
    trigger array st__B_someMethod
    integer array si__A_type
    integer array si__A_2type
    integer array si__A_3type
    trigger array st__A_onDestroy
    integer f__arg_this
    integer f__result_integer

    endglobals


    function si__A_getType takes integer this returns integer
        if(this<8191) then
            return si__A_type[this]
        else
            return si__A_2type[this-8191]
        endif
    endfunction

    function si__B_getType takes integer this returns integer
        if(this<8191) then
            return si__B_type[this]
        else
            return si__B_2type[this-8191]
        endif
    endfunction

    //Generated method caller for A.someMethod
    function sc__A_someMethod takes integer this returns integer
        set f__arg_this=this
        if(this<8191) then
                call TriggerEvaluate(st__A_someMethod[si__A_type[this]])
        else
                call TriggerEvaluate(st__A_someMethod[si__A_2type[this-8191]])
        endif
     return f__result_integer
    endfunction

    //Generated allocator of A
    function s__A__allocate takes nothing returns integer
     local integer this=si__A_F
        if (this!=0) then
            if(this<8191) then
                set si__A_F=si__A_V[this]
            else
                set si__A_F=si__A_2V[this-8191]
            endif
        else
            set si__A_I=si__A_I+1
            set this=si__A_I
        endif
        if (this>16382) then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Unable to allocate id for an object of type: A")
            return 0
        endif

        if(this<8191) then
            set si__A_type[this]=1
        else
            set si__A_2type[this-8191]=1
        endif
        if(this<8191) then
            set si__A_V[this]=-1
        else
            set si__A_2V[this-8191]=-1
        endif
     return this
    endfunction

    //Generated destructor of A
    function sc__A_deallocate takes integer this returns nothing
     local integer used
        if this==null then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: A")
            return
        else
            if(this<8191) then
                set used=si__A_V[this]
            else
                set used=si__A_2V[this-8191]
            endif
            if (used!=-1) then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: A")
                return
            endif
        endif
        set f__arg_this=this
        if(this<8191) then
            call TriggerEvaluate(st__A_onDestroy[si__A_type[this]])
        else
            call TriggerEvaluate(st__A_onDestroy[si__A_2type[this-8191]])
        endif
        if(this<8191) then
            set si__A_V[this]=si__A_F
        else
            set si__A_2V[this-8191]=si__A_F
        endif
        set si__A_F=this
    endfunction

    //Generated method caller for B.someMethod
    function sc__B_someMethod takes integer this returns integer
        set f__arg_this=this
        if(this<8191) then
                call TriggerEvaluate(st__A_someMethod[si__B_type[this]])
        else
                call TriggerEvaluate(st__A_someMethod[si__B_2type[this-8191]])
        endif
     return f__result_integer
    endfunction

    //Generated allocator of B
    function s__B__allocate takes nothing returns integer
     local integer this=s__A__allocate()
     local integer kthis
        if(this==0) then
            return 0
        endif
        if(this<8191) then
            set si__A_type[this]=2
        else
            set si__A_2type[this-8191]=2
        endif
        set kthis=this

     return this
    endfunction


    //Generated method caller for C.someMethod
    function sc__C_someMethod takes integer this returns integer
            return 3
    endfunction

    //Generated allocator of C
    function s__C__allocate takes nothing returns integer
     local integer this=s__B__allocate()
     local integer kthis
        if(this==0) then
            return 0
        endif
        if(this<8191) then
            set si__A_type[this]=3
        else
            set si__A_2type[this-8191]=3
        endif
        set kthis=this

     return this
    endfunction

    // ...

    function jasshelper__initstructs45407515 takes nothing returns nothing
        set st__A_someMethod[1]=CreateTrigger()
        call TriggerAddCondition(st__A_someMethod[1],Condition( function sa__A_someMethod))
        call TriggerAddAction(st__A_someMethod[1], function sa__A_someMethod)
        set st__A_onDestroy[1]=null
        set st__A_onDestroy[2]=null
        set st__A_onDestroy[3]=null
        set st__A_someMethod[2]=CreateTrigger()
        call TriggerAddCondition(st__A_someMethod[2],Condition( function sa__B_someMethod))
        call TriggerAddAction(st__A_someMethod[2], function sa__B_someMethod)
        set st__A_someMethod[3]=CreateTrigger()
        call TriggerAddCondition(st__A_someMethod[3],Condition( function sa__C_someMethod))
        call TriggerAddAction(st__A_someMethod[3], function sa__C_someMethod)
    endfunction

    Function
    sc__B_someMethod
    uses
    integer array si__B_type
    and
    integer array si__B_2type
    which are never filled, therefore, no method will be called as no struct has type 0.


    Forth issue is similar.
    Code (vJASS):
    struct A[16382]
    endstruct

    struct B extends A
        stub method someMethod takes nothing returns integer
            return 2
        endmethod
    endstruct

    struct C extends B
        method someMethod takes nothing returns integer
            return 3
        endmethod
    endstruct

    globals
        integer array si__B_type
        integer array si__B_2type
    endglobals

    Compilation produces next error.
    [​IMG]

    Let's declare
    trigger array st__A_someMethod
    and compile.
    Code (vJASS):
    globals
        // Generated
    integer array si__B_type
    integer array si__B_2type
    trigger array st__A_someMethod


    //JASSHelper struct globals:
    constant integer si__A=1
    integer si__A_F=0
    integer si__A_I=0
    integer array si__A_V
    integer array si__A_2V
    integer array si__A_3V
    constant integer si__B=2
    constant integer si__C=3
    trigger array st__B_someMethod
    integer array si__A_type
    integer array si__A_2type
    integer array si__A_3type
    trigger array st__A_onDestroy
    integer f__arg_this
    integer f__result_integer

    endglobals


    function si__A_getType takes integer this returns integer
        if(this<8191) then
            return si__A_type[this]
        else
            return si__A_2type[this-8191]
        endif
    endfunction

    function si__B_getType takes integer this returns integer
        if(this<8191) then
            return si__B_type[this]
        else
            return si__B_2type[this-8191]
        endif
    endfunction

    //Generated allocator of A
    function s__A__allocate takes nothing returns integer
     local integer this=si__A_F
        if (this!=0) then
            if(this<8191) then
                set si__A_F=si__A_V[this]
            else
                set si__A_F=si__A_2V[this-8191]
            endif
        else
            set si__A_I=si__A_I+1
            set this=si__A_I
        endif
        if (this>16382) then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Unable to allocate id for an object of type: A")
            return 0
        endif

        if(this<8191) then
            set si__A_type[this]=1
        else
            set si__A_2type[this-8191]=1
        endif
        if(this<8191) then
            set si__A_V[this]=-1
        else
            set si__A_2V[this-8191]=-1
        endif
     return this
    endfunction

    //Generated destructor of A
    function sc__A_deallocate takes integer this returns nothing
     local integer used
        if this==null then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: A")
            return
        else
            if(this<8191) then
                set used=si__A_V[this]
            else
                set used=si__A_2V[this-8191]
            endif
            if (used!=-1) then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: A")
                return
            endif
        endif
        set f__arg_this=this
        if(this<8191) then
            call TriggerEvaluate(st__A_onDestroy[si__A_type[this]])
        else
            call TriggerEvaluate(st__A_onDestroy[si__A_2type[this-8191]])
        endif
        if(this<8191) then
            set si__A_V[this]=si__A_F
        else
            set si__A_2V[this-8191]=si__A_F
        endif
        set si__A_F=this
    endfunction

    //Generated method caller for B.someMethod
    function sc__B_someMethod takes integer this returns integer
        set f__arg_this=this
        if(this<8191) then
                call TriggerEvaluate(st__A_someMethod[si__B_type[this]])
        else
                call TriggerEvaluate(st__A_someMethod[si__B_2type[this-8191]])
        endif
     return f__result_integer
    endfunction

    //Generated allocator of B
    function s__B__allocate takes nothing returns integer
     local integer this=s__A__allocate()
     local integer kthis
        if(this==0) then
            return 0
        endif
        if(this<8191) then
            set si__A_type[this]=2
        else
            set si__A_2type[this-8191]=2
        endif
        set kthis=this

     return this
    endfunction


    //Generated method caller for C.someMethod
    function sc__C_someMethod takes integer this returns integer
            return 3
    endfunction

    //Generated allocator of C
    function s__C__allocate takes nothing returns integer
     local integer this=s__B__allocate()
     local integer kthis
        if(this==0) then
            return 0
        endif
        if(this<8191) then
            set si__A_type[this]=3
        else
            set si__A_2type[this-8191]=3
        endif
        set kthis=this

     return this
    endfunction

    // ...

    function jasshelper__initstructs45097343 takes nothing returns nothing
        set st__A_onDestroy[1]=null
        set st__A_onDestroy[2]=null
        set st__A_onDestroy[3]=null
        set st__B_someMethod[2]=CreateTrigger()
        call TriggerAddCondition(st__B_someMethod[2],Condition( function sa__B_someMethod))
        call TriggerAddAction(st__B_someMethod[2], function sa__B_someMethod)
        set st__B_someMethod[3]=CreateTrigger()
        call TriggerAddCondition(st__B_someMethod[3],Condition( function sa__C_someMethod))
        call TriggerAddAction(st__B_someMethod[3], function sa__C_someMethod)
    endfunction

    Here function
    sc__B_someMethod
    is totally broken. It uses empty
    integer array si__B_type
    ,
    integer array si__B_2type
    and
    trigger array st__A_someMethod
    .


    The most interesting thing is that second and forth issues are handled if struct uses the number of indexes less than 8191.
    If the number of indexes is 8191, issues 2-4 take place.


    Fifth issue. The most important.
    Let's consider code from third issue but for struct with the numer of indexes less than 8191.
    Code (vJASS):
    struct A
        stub method someMethod takes nothing returns integer
            return 1
        endmethod
    endstruct

    struct B extends A
        stub method someMethod takes nothing returns integer
            return 2
        endmethod
    endstruct

    struct C extends B
        method someMethod takes nothing returns integer
            return 3
        endmethod
    endstruct

    Code (vJASS):
    globals
        // Generated
    trigger gg_trg_GeneratedCode= null
        //integer array si__B_type
        //integer array si__B_2type
        //trigger array st__A_someMethod


    //JASSHelper struct globals:
    constant integer si__A=1
    integer si__A_F=0
    integer si__A_I=0
    integer array si__A_V
    constant integer si__B=2
    constant integer si__C=3
    trigger array st__A_someMethod
    trigger array st__B_someMethod
    integer array si__A_type
    trigger array st__A_onDestroy
    integer f__arg_this
    integer f__result_integer

    endglobals


    //Generated method caller for A.someMethod
    function sc__A_someMethod takes integer this returns integer
        set f__arg_this=this
        call TriggerEvaluate(st__A_someMethod[si__A_type[this]])
     return f__result_integer
    endfunction

    //Generated allocator of A
    function s__A__allocate takes nothing returns integer
     local integer this=si__A_F
        if (this!=0) then
            set si__A_F=si__A_V[this]
        else
            set si__A_I=si__A_I+1
            set this=si__A_I
        endif
        if (this>8190) then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Unable to allocate id for an object of type: A")
            return 0
        endif

        set si__A_type[this]=1
        set si__A_V[this]=-1
     return this
    endfunction

    //Generated destructor of A
    function sc__A_deallocate takes integer this returns nothing
        if this==null then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: A")
            return
        elseif (si__A_V[this]!=-1) then
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: A")
            return
        endif
        set f__arg_this=this
        call TriggerEvaluate(st__A_onDestroy[si__A_type[this]])
        set si__A_V[this]=si__A_F
        set si__A_F=this
    endfunction

    //Generated method caller for B.someMethod
    function sc__B_someMethod takes integer this returns integer
        set f__arg_this=this
        call TriggerEvaluate(st__B_someMethod[si__A_type[this]])
     return f__result_integer
    endfunction

    //Generated allocator of B
    function s__B__allocate takes nothing returns integer
     local integer this=s__A__allocate()
     local integer kthis
        if(this==0) then
            return 0
        endif
        set si__A_type[this]=2
        set kthis=this

     return this
    endfunction


    //Generated method caller for C.someMethod
    function sc__C_someMethod takes integer this returns integer
            return 3
    endfunction

    //Generated allocator of C
    function s__C__allocate takes nothing returns integer
     local integer this=s__B__allocate()
     local integer kthis
        if(this==0) then
            return 0
        endif
        set si__A_type[this]=3
        set kthis=this

     return this
    endfunction

    // ...

    function jasshelper__initstructs46862484 takes nothing returns nothing
        set st__A_someMethod[1]=CreateTrigger()
        call TriggerAddCondition(st__A_someMethod[1],Condition( function sa__A_someMethod))
        call TriggerAddAction(st__A_someMethod[1], function sa__A_someMethod)
        set st__A_onDestroy[1]=null
        set st__A_onDestroy[2]=null
        set st__A_onDestroy[3]=null
        set st__A_someMethod[2]=CreateTrigger()
        call TriggerAddCondition(st__A_someMethod[2],Condition( function sa__B_someMethod))
        call TriggerAddAction(st__A_someMethod[2], function sa__B_someMethod)
        set st__A_someMethod[3]=CreateTrigger()
        call TriggerAddCondition(st__A_someMethod[3],Condition( function sa__C_someMethod))
        call TriggerAddAction(st__A_someMethod[3], function sa__C_someMethod)
    endfunction

    Function
    sc__B_someMethod
    uses empty
    trigger array st__B_someMethod
    , thus, no actions will be done.


    I have to mention next thing.
    Code (vJASS):
    function f takes nothing returns nothing
        local B b = C.create()
        call DisplayTextToPlayer(Player(0), 0., 0., I2S(b.someMethod()))
    endfunction

    Code above will be converted to code below in all third, forth and fifth issues.
    Code (vJASS):
    function f takes nothing returns nothing
        local integer b= s__C__allocate()
        call DisplayTextToPlayer(Player(0), 0., 0., I2S(sc__A_someMethod(b)))
    endfunction

    Here it's clearly shown that function
    sc__B_someMethod
    is totally useless, and all bugs connected with it can be ignored.
    UPD: Actually, for forth issue next code is generated.
    Code (vJASS):
    function f takes nothing returns nothing
        local integer b= s__C__allocate()
        call DisplayTextToPlayer(Player(0), 0., 0., I2S(sc__B_someMethod(b)))
    endfunction

    This is the only really weird issue. I remind you that this issue is handled for structs with the number of indexes less than 8191.




    It is time to conclude. There can be more issues if, for example, struct D extends C and so on, but I do not investigate it. I hope that someone will fix these issues and share with fixed version of JassHelper.
    The key points:

    • For structs with the number of indexes which equals to multipliers of 8191, JassHelper generates arrays which are never used.
    • For structs with the number of indexes which equals to any integer in range (8191 * k, 8192 * k - 1], where k > 1, JassHelper generates more arrays than it's really needed.
    • For structs with the number of indexes more than 8190 and with descendants which have their own descendants, JassHelper generates functions of getting type for intermediate parents. These functions are never used.
    • Consider next struct: it has stub methods, descendants in which these methods are also stub, and its descendants have their own descendants. JassHelper generates callers for mentioned stub methods which are never used.
    • Consider next struct: it uses the number of indexes greater than 8190, has descendants which have stub methods and their own descendants. JassHelper generates broken callers for mentioned stub methods.


    Be careful when you extend structs!
     

    Attached Files:

    Last edited: Sep 3, 2018
  2. Prometheus3375

    Prometheus3375

    Joined:
    Jul 20, 2018
    Messages:
    31
    Resources:
    0
    Resources:
    0
    It would be great if someone share a link to source code of JassHelper.
     
  3. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,538
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
  4. Prometheus3375

    Prometheus3375

    Joined:
    Jul 20, 2018
    Messages:
    31
    Resources:
    0
    Resources:
    0
    Thanks a lot! But I need to register there to download.
    UPD 04.02.2019: well, now registration is not necessary (and maybe even was not necessary).


    I updated post a bit, I had found mistakes connected with forth issue.
     
    Last edited: Feb 3, 2019
  5. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,776
    Resources:
    11
    Models:
    4
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    11
    All I can say is: if you want to go beyond the 8191 limit of regular structs, use a hashtable instead.
    The hacks Jasshelper uses to implement larger arrays are usually not very speed efficient and hashtables offer a variety of other functions for your convenience, like flushing, etc.
     
  6. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,538
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    In 1.29+ the array size is much larger so extending the struct and adding your own allocation can work too if you don't want to use a hashtable.
     
  7. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,776
    Resources:
    11
    Models:
    4
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    11
    Didn't know that. Then again, the struct limit was rarely an issue unless you were coding system fundamentals, of which most of them have been engineered to death already or might be replaced with new systems making use of the modern natives.
     
  8. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    1,757
    Resources:
    0
    Resources:
    0
    I mean is that really that hard to do? Wc3c sends 1 email a year: a happy birthday on your birthday if you tell the site when that is.
     
  9. Prometheus3375

    Prometheus3375

    Joined:
    Jul 20, 2018
    Messages:
    31
    Resources:
    0
    Resources:
    0
    Found another issue, it is not possible to
    .execute()
    a
    create()
    method.
    Code (vJASS):
    struct U
    endstruct

    function h takes nothing returns nothing
        local integer k = U.create.execute()
    endfunction
     
    [​IMG]

    vJass tells that
    create()
    method is internal. OK, let's declare it.

    Code (vJASS):
    struct U
        static method create takes nothing returns thistype
            return allocate()
        endmethod
    endstruct

    function h takes nothing returns nothing
        local integer k = U.create.execute()
    endfunction
     
    [​IMG]

    vJass forgot to add
    return f__result_integer
    to executer.
    [​IMG]
     

    Attached Files:

    Last edited: Feb 2, 2019
  10. Prometheus3375

    Prometheus3375

    Joined:
    Jul 20, 2018
    Messages:
    31
    Resources:
    0
    Resources:
    0
    UPD: the issue above takes place for any method.
    UPD2: lol, it seems like any executor (not only for structs) cannot return values.
     
  11. Overfrost

    Overfrost

    Joined:
    Jan 9, 2019
    Messages:
    82
    Resources:
    0
    Resources:
    0
    The thing is... vJASS users nowadays don't even bother seeing structs as what they're supposed to be. Because many of its features are regarded as "bad" due to the extra codes it generates just to emulate them. Some feature is widely known already to cause unnecessary overheads.

    FYI, here's what vJASS does nowadays:
    Code (vJASS):
    library SomeLibrary requires Alloc, AnotherLibrary  // 1. scope
    // Alloc is required here for demonstration purposes
    // it is the general library for optimized struct allocators

        private module SystemInitializer  // 2. system-initializer
            private static method onInit takes nothing returns nothing
                call thistype.initialize()
            endmethod
        endmodule
        struct FancyWrapper extends array  // 3. fancy wrapper, seriously
        // extending array means jasshelper won't generate any allocator/deallocator for it

            implement Alloc  // make it classy

            static method operator [] takes integer i returns integer
                return i*2
            endmethod  // or make it fancy-wrapper-only

            method operator x takes nothing returns real
                return this
            endmethod  // fancy variable handler
            method operator x= takes real ax returns thistype
                return R2I(ax)
            endmethod  // this one usually returns nothing, but it's here for completeness
            // readonly is common, but I've never seen setonly even though it is doable

            private static method initialize takes nothing returns nothing
                // initialize stuffs
            endmethod
            implement SystemInitializer
        endstruct

    endlibrary
    Plus, textmacro is very powerful in terms of managing optimized codes. Function-inlining feature is also something that must not be missed from using jasshelper.
     
    Last edited: Feb 10, 2019 at 4:52 PM
  12. Prometheus3375

    Prometheus3375

    Joined:
    Jul 20, 2018
    Messages:
    31
    Resources:
    0
    Resources:
    0
    And that's why I do not see any usefulness of modules, since textmacros have more options than modules.

    Watched BestAlloc link: very interesting, but author of that code forgot that
    static if
    supports
    not
    and
    and
    operators. I. e.
    static if LIBRARY_MemoryAnalysis and DEBUG_MODE then
    works.



    I watched the source code and for some reason Vexorian decided that executers should not have the return value. I probably have fixed that, but it's topic for a new thread.
     
  13. Overfrost

    Overfrost

    Joined:
    Jan 9, 2019
    Messages:
    82
    Resources:
    0
    Resources:
    0
    Module is used for proper inheritance API (in a rather abusive sense). The main difference between modules and textmacros is that only one module can be implemented in each struct, and modules can be nested, plus modules can have private members. So:
    Code (vJASS):
    module A
        real x
        real y
    endmodule
    module B
        implement A
        real z
        private integer index
    endmodule
    struct S extends array  // usual array-extending
        implement B  // also has A
        implement A  // unneeded, but fine, won't raise any error, nor make more members

        // has:
        //   real x
        //   real y
        //   real z
    endstruct
    // but modules can't make private members for the struct
    There's no way he forgot about that, he's a pro. And that won't make much difference anyway. It's about his preference of the debug keyword over DEBUG_MODE.