• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Issues with structs in vJass

Status
Not open for further replies.
Level 9
Joined
Jul 20, 2018
Messages
176
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.
JASS:
struct A[8191]
endstruct
There is generated code below.
JASS:
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.
JASS:
struct A[16382]
endstruct

struct B extends A
endstruct

struct C extends B
endstruct
If you compile it, next message will be thrown.
%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-06-png.305676

For some reason JassHelper forgets to generate some variables. OK, let's do it by our own.
JASS:
globals
    integer array si__B_type
    integer array si__B_2type
endglobals
After compilation next code will be generated.
JASS:
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.
JASS:
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
JASS:
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.
JASS:
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.
%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-07-png.305677

Let's declare trigger array st__A_someMethod and compile.
JASS:
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.
JASS:
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
JASS:
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.
JASS:
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.
JASS:
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.
JASS:
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!
 

Attachments

  • Снимок 06.PNG
    Снимок 06.PNG
    28.4 KB · Views: 414
  • Снимок 07.PNG
    Снимок 07.PNG
    31 KB · Views: 423
Last edited:
Level 9
Joined
Jul 20, 2018
Messages
176
JassHelper 0.A.2.B - A vJass and Zinc 2 Jass compiler - Wc3C.net
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:
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.

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.
 
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.
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.
 
Level 9
Joined
Jul 20, 2018
Messages
176
Found another issue, it is not possible to .execute() a create() method.
JASS:
struct U
endstruct

function h takes nothing returns nothing
    local integer k = U.create.execute()
endfunction
%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-64-png.315218

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

JASS:
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
%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-65-png.315224

vJass forgot to add return f__result_integer to executer.
%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-67-png.315225
 

Attachments

  • Снимок 64.PNG
    Снимок 64.PNG
    24.2 KB · Views: 325
  • Снимок 65.PNG
    Снимок 65.PNG
    23 KB · Views: 294
  • Снимок 67.PNG
    Снимок 67.PNG
    28.2 KB · Views: 359
Last edited:
Level 6
Joined
Jan 9, 2019
Messages
102
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:
JASS:
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:
Level 9
Joined
Jul 20, 2018
Messages
176
Plus, textmacro is very powerful in terms of managing optimized codes.
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.



it seems like any executor (not only for structs) cannot return values.
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.
 
Level 6
Joined
Jan 9, 2019
Messages
102
And that's why I do not see any usefulness of modules, since textmacros have more options than modules.
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:
JASS:
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
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.
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.
 
Status
Not open for further replies.
Top