TL;DR
function fn(){
let a = static {x: 0}
a.x++
return a
}
console.assert(fn().x == 1)
console.assert(fn().x == 2)
console.assert(fn().x == 3)
const o = fn()
console.assert(fn() == fn() && fn() == o)
o.x = 99
console.assert(fn().x == 100)
Give additional functionality to the static
keyword, to statically allocate an object
I.e, the expression following the static
keyword would only be evaluated once, and never again, even if it is found inside a function or loop. The static
expression would then return the same value every time.
Example use cases
Consider the current solution to a hypothetical problem:
const privateSymbol = Symbol('hidden')
function processObject(obj){
if(obj[privateSymbol]) return obj[privateSymbol]
//...
// perform some processing
//...
obj[privateSymbol] = processedValue
return processedValue
}
Despite this, privateSymbol
remains exposed. We could create an IIFE or some other kind of closure,
var processObject
{
const privateSymbol = Symbol('hidden')
processObject = function(obj){
if(obj[privateSymbol]) return obj[privateSymbol]
//...
// perform some processing
//...
obj[privateSymbol] = processedValue
return processedValue
}
}
However, it would make more sense if we didn't have to define the symbol outside the function
function processObject(obj){
const privateSymbol = Symbol('hidden')
// .....
}
Unfortunately, now, our private symbol will be different with each call to the function.
In this proposal, the static
keyword would be able to turn an expression inside a function (or loop, or anything else really) into a statically evaluted one,
function processObject(obj){
// This expression will evaluate to the same each time
const privateSymbol = static Symbol('hidden')
if(obj[privateSymbol]) return obj[privateSymbol]
//...
// perform some processing
//...
obj[privateSymbol] = processedValue
return processedValue
}
Other use cases
In react, it's not uncommon to declare styles inline, directly inside a component, e.g
const MyComponent = () => {
return <div style={ {color: 'red', fontSize: 30, cursor: 'pointer'} }>
Hello!
</div>
}
React would then have to parse the style
object and turn it into a style declaration every time the component is rerendered, which is a lot of work, and it perhaps one of react's biggest performance downfall, especially noticable when using large complex apps like Discord
The static
keyword would allow a cache-like optimization, where an object could be recognised, and would not require re-parsing, e.g
function styleObjectToCss(obj){
const cachedCss = static Symbol('cachedCss')
// If the object has been seen before, use its cached value
if(obj[cachedCss]) return obj[cachedCss]
// Otherwise, perform expensive conversion
const cssText = ...(obj)
obj[cachedCss] = cssText
return cssText
}
And our component would look like this
const MyComponent = () => {
return <div style={ static {color: 'red', fontSize: 30, cursor: 'pointer'} }>
Hello!
</div>
}
static
would allow the same object to be passed each time, essentially allowing react to easily cache its css representation and only process our object once.
Other use cases
There plenty other use cases that would be made simpler with the static
keyword, here are a few examples:
-
sha256 uses a precomputed table of fractional digits of
sqrt(2)
-
Functions can now be organized inside other functions without worrying about capturing or performance overhead (e.g when an exported function
thing
is a wrapper to the real function called_thing
) -
Node uses objects as option parameters absolutely everywhere. Using static would allocate the object on the heap, but would only do so once during the entire duration of the program.
Important noteworthy point: Since each static object is allocated once only, it does not ever need to be garbage collected, meaning less memory and performance overhead for using that object
Unlike most other convenience feature, this feature provides a clear performance benefit over our current closest equivalent.
Extensions
These are possible extensions to this proposal, feel free to suggest edits as I have not given deep thought to most of these.
Native functions' return values
This subheading does not directly concern the static
syntax, but rather the internal workings of native functions, that would likely be implemented in C++
Currently, Generator#next()
returns a new object like {value: any, done: boolean}
. This object is dynamically allocated and different every time. This object could be statically allocated with its values mutated every time, potentially increasing performance substantially (although I expect the difference would be less significant the more sophisticated the JS runtime is)
Similarly, Map
entry iterators return an array on each iteration. This array could also be statically allocated.
There are many other functions, native or not, that typically return dynamically allocated objects, such as TextEncoder#encode()
or React's useState
Static variable declaration
Best described by an example, this would work similarly to classes' static
, and would be specific to each function, essentially inheriting its function's lifetime.
function count(){
static current = 0
current++
return current
}
console.assert(count() == 1)
console.assert(count() == 2)
console.assert(count() == 3)
console.assert(count.current == 3)
Let me know what you think!