- Joined
- Oct 19, 2014
- Messages
- 187
Can anyway one answer my question,, what should i do on Extend Array?? 



Depends, if you dynamically create the struct, then you should have their own allocation and deallocation method. But instead of doing that, why don't you just use a normal struct instead? (or implement Alloc resources like this or this). People usually use an Alloc resource for less script generated and the debugging features it offers.what should i do on Extend Array??
A lot of what he wrote is not technically correct though.
Child.allocate()
will call Parent.create()
, not Parent.allocate()
as his description states. The other descriptions seem similarly confused. It seems a lot simpler to me to simply say that child's allocate and deallocate methods will always call parent's create and destroy, which are then expected to call the parent's allocate and deallocate internally, and so the cycle continues through the inheritance tree. If you don't declare a custom create method, then the default method gets used which is just an allocate call so it gets inlined, so yes in this case the child's allocator will technically call the parent's allocator directly, but that's a special case and doesn't really work as a general explanation.In the case of singleton structs this would be massive performance improvement as non-array variables could be used.
struct my_global_vars_aka_singleton extends array
integer foo = 5
real tau = 6.2831
endstruct
call BJDebugMsg(I2S(my_global_vars_aka_singleton.foo))
Why structs are implemented like this I will never understand. They should rather have been kept a type in the form of grouped variables. Allocation and struct references should then have been done from a "memory bank" which implements a referencing scheme and allocation model for a struct type. When generating method implementations the compiler would then produce functions for each declaration of the type, inlining when appropriate. This would allow you to pass by value structs as parameters, declare multiple banks for struct types and declare multiple struct arrays. In the case of singleton structs this would be massive performance improvement as non-array variables could be used. It certainly would be a lot cleaner than the vJASS implementation as it would not have such obscure syntax and unintuitive mechanics.
struct my_global_vars_aka_singleton extends array
integer foo = 5
real tau = 6.2831
endstruct
call BJDebugMsg(I2S(my_global_vars_aka_singleton.foo))
struct struct_t
integer foo = 5
real bar = 6.2831
endstruct
globals
struct_t singleton
struct_t array[16] structarray // size needed for initializer, index 16+ not initialized
endglobals
// example usage
call BJDebugMsg(I2S(singleton.foo))
call BJDebugMsg(R2S(singleton.bar))
call BJDebugMsg(I2S(structarray[0].foo))
call BJDebugMsg(R2S(structarray[15].bar))
struct struct_t
integer foo = 5
real bar = 6.2831
endstruct
globals
integer struct_t_singleton_foo = 5
real struct_t_singleton_bar = 6.2831
integer array struct_t_structarray_foo
real array struct_t_structarray_bar
endglobals
// following code run on initialization
local integer i = 0
loop
set struct_t_structarray_foo[i] = 5
set struct_t_structarray_bar[i] = 6.2831
set i = i + 1
exitwhen i >= 16
endloop
// example usage code
call BJDebugMsg(I2S(struct_t_singleton_foo))
call BJDebugMsg(R2S(struct_t_singleton_bar))
call BJDebugMsg(I2S(struct_t_structarray_foo[0]))
call BJDebugMsg(R2S(struct_t_structarray_bar[15]))
struct struct_t
integer foo = 5
real bar = 6.2831
endstruct
// a new system is needed for memory bank definitions, there would be a few standard implementations built in
bankdef
....
endbankdef
bankmap
dynamic struct_t struct_tr // same allocation model as standard vJASS new/delete
// one can explicitly name banks, needed for OOP stuff so that child types will share the same bank
// dynamic<std> struct_t struct_tr // functionally same as above, std name space used by default
// new allocation model for explicit size support (more than 8192 instances supported)
// sized<std, 20000> struct_t struct_tr
// new allocation model with hashtable backing instead of array
// hashed<std> struct_t struct_tr
endbankmap
// example usage
local struct_tr obj
set obj = new struct_t()
call BJDebugMsg(I2S(obj.foo))
call BJDebugMsg(R2S(obj.bar))
delete obj
// example usage with generic cross bank references, these are slow so should never really be used
local struct_tr obj
local struct_t reference obj2
set obj = new struct_t()
set obj2 = obj // implementation for bank operations is passed in the form of a virtual function table as well as struct address
// set obj2 = new struct_t() // not legal, unknown bank to use to allocate
// set obj = obj2 // only legal if obj instance references same bank type as obj tested using virtual function table reference, otherwise error is thrown and thread crashed
delete obj2 // virtual functions used for this as well
This would then produce optimized code some what like...
JASS:struct struct_t integer foo = 5 real bar = 6.2831 endstruct globals integer struct_t_singleton_foo = 5 real struct_t_singleton_bar = 6.2831 integer array struct_t_structarray_foo real array struct_t_structarray_bar endglobals // following code run on initialization local integer i = 0 loop set struct_t_structarray_foo[i] = 5 set struct_t_structarray_bar[i] = 6.2831 set i = i + 1 exitwhen i >= 16 endloop // example usage code call BJDebugMsg(I2S(struct_t_singleton_foo)) call BJDebugMsg(R2S(struct_t_singleton_bar)) call BJDebugMsg(I2S(struct_t_structarray_foo[0])) call BJDebugMsg(R2S(struct_t_structarray_bar[15]))
struct struct_t
integer foo = 5
real bar = 6.2831
endstruct
globals
struct_t A
// integer struct_t_A_foo = 5
// real struct_t_A_bar = 6.2831
struct_t B
// integer struct_t_B_foo = 5
// real struct_t_B_bar = 6.2831
struct_t array[16] my_struct_t_array
// integer array my_struct_t_array_foo
// real array my_struct_t_array_bar
endglobals
function my_func takes struct_t s returns nothing
// function my_func takes integer s_foo, real s_bar returns nothing
local real baz = s.foo + s.bar
// local real baz = s_foo + s_bar
endfunction
function returing_struct_t takes nothing returns struct_t
local struct_t result
set result.foo = GetRandomInt(1, 100)
set result.bar = GetRandomReal(0, 1)
return result
// globals
// integer return_struct_t_foo
// real return_struct_t_bar
// endglobals
//
// set return_struct_t_foo = struct_t_result_foo
// set return_struct_t_bar = struct_t_result_bar
//
// on the call site
// set my_struct_t = reuturing_struct_t()
// set struct_t_my_struct_t_foo = return_struct_t_foo
// set struct_t_my_struct_t_bar = return_struct_t_bar
endfunction
function main takes nothing returns nothing
local struct_t C
// globals
// integer local_struct_t_C_foo = 5
// real local_struct_t_C_bar = 6.2831
// endglobals
call my_func(A)
// call my_func(struct_t_A_foo, struct_t_A_bar)
call my_func(B)
// call my_func(struct_t_B_foo, struct_t_B_bar)
if GetRandomReal(0, 1) < 0.5 then
set C = A
// set local_struct_t_C_foo = struct_t_A_foo
// set local_struct_t_C_bar = struct_t_A_bar
else
set C = B
// set local_struct_t_C_foo = struct_t_B_foo
// set local_struct_t_C_bar = struct_t_B_bar
endif
call my_func(C)
// call my_func(local_struct_t_C_foo, local_struct_t_C_bar)
// if struct_t has a lot of members that could be problematic if there's a limit on the number arguments a function could take,
// and it might be the case that calling a function with more arguments is slower, idk...
call my_func(my_struct_t_array[GetRandomInt(0, 15)])
// set i_expr_1 = GetRandomInt(0, 15)
// call my_func(my_struct_t_array_foo[i_expr_1], my_struct_t_array_bar[i_expr_1])
endfunction
struct A
integer foo = 1
real bar = 2.0
endstruct
struct B
A a
string baz = "=)"
endstruct
globals
A some_a
// integer A_some_a_foo = 1
// real A_some_a_bar = 2.0
B some_b
// integer B_some_b_A_foo = 1
// real B_some_b_A_bar = 2.0
// integer B_some_b_baz = "=)"
endglobals
By value. Basically each struct member then becomes a function parameter. This is very good for inlining as methods could be unwound and work directly on the function parameters. Returning structs would need "register globals" since you are limited to returning only one argument, these register globals would then be copied to locals after function return based on how the value is used.Well if each struct declaration created it's own backing global variables how would you pass/return structs to/from functions?
You would mostly want to work with structs in their current form, which is provided by the bank mechanics to reference them.Could work, I guess... Although there's a limit on the number of global variables (~25_000) so that might also be a problem.
Current structs are aimed at dynamic memory allocation and do so by backing every member variable with an array of the same type to form a memory bank. Struct types are then references within this memory bank to the struct instance. A memory model with the memory bank allows for dynamic allocation and deallocation of structs.You lost me on the "dynamic part", though.
As far as I am aware that will not compile and it will still create backing arrays.JASS:struct my_global_vars_aka_singleton extends array integer foo = 5 real tau = 6.2831 endstruct call BJDebugMsg(I2S(my_global_vars_aka_singleton.foo))
struct my_global_vars_aka_singleton extends array
static integer foo = 5
static real tau = 6.2831
endstruct
call BJDebugMsg(I2S(my_global_vars_aka_singleton.foo))
There, fixed.
The bank feature is needed due to a lack of generic storage space being part of the language. Instead storage space has to be simulated using language features, and hence multiple implementations can exist.I think vJass is fine the way it is. So what if a vJass struct is closer to a Java class than a C struct? So what if the implementation isn't perfectly generalised or whatever other abstract concepts you're complaining about. It's useful, and if anything your suggestions so far seemed less useful by comparison. So for each struct I'd first need to declare a struct, then a bank, then who knows what else?
Yes, making life make more sense is why it is a great editor. No "local declared local handle variable reference counter leak on return" there.This might be how the SC2 data editor came to be.