roblox-ts / roblox-ts

A TypeScript-to-Luau Compiler for Roblox
https://roblox-ts.com/
MIT License
899 stars 130 forks source link

Make it so you can initialize arrays of a certain length #298

Closed Validark closed 5 years ago

Validark commented 5 years ago

In regular TS/JS you can initialize arrays of a predefined length. This is useful for performance critical code where one can benefit from not resizing the dynamically-sized array several times. The single parameter is nice sugar we could easily integrate into the transpiler.

const strings = new Array<string>(12);
local strings = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Kinrany commented 5 years ago

Would this have the same performance benefits?

Does Roblox have a maximum file size limit, or could there be any other file size-related problems?

Is there another way to initialize large arrays in Lua?

osyrisrblx commented 5 years ago

Every time a Lua array runs out of allocated memory, it will double in size. So there is some perf gain in allocating it all at once.

osyrisrblx commented 5 years ago

However, filling an array of strings with zeroes is kinda weird..

Validark commented 5 years ago

How about this?

local t = {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}

Here is what this compiles to in bytecode (Lua 5.3):

main <test.lua:0,0> (6 instructions at 0000000000b01ea0)
0+ params, 18 slots, 1 upvalue, 1 local, 0 constants, 0 functions
        1       [4]     NEWTABLE        0 17 0
        2       [4]     LOADNIL         1 16
        3       [4]     SETLIST         0 17 1  ; 1
brianush1 commented 5 years ago

There isn't much of a gain there; for large array sizes, let's say of 1 million entries, that's 1,000,000*4+1=4,000,001 characters for a single table, whereas it would only take ceil(log2(1,000,000))=20 reallocations to get to an array of 1 million entries. It would run marginally faster at runtime and take a lot longer to compile.

Validark commented 5 years ago

Firstly, avoiding 20 reallocations at run-time involving hundreds of thousands of elements being deleted and copied is more than "marginally faster", although that is not the use-case or reason JS and Lua have shortcuts for these.

Lua has a built-in optimization for this that can initialize up to 50 nil values in an array at a time. That would probably be the maximum number of nil values you would ever want to put into a script in-line (or maybe 100 nil values, which would be 4 bytecode instructions). For insane cases where someone wants to allocate a million entries, we could either fallback on a for loop or just let Lua run that dynamically.

evaera commented 5 years ago

I think it should be noted that in regular JS/TS, presizing arrays does not actually allocate anything (all it does it set the length property) and in fact has the inverse effect and reduces the performance of the array significantly for as long as the object exists (even if it's filled in later)