Quando você está implementando um idioma digitado dinamicamente, você precisa ter um único tipo que possa conter qualquer um dos seus objetos. Existem três abordagens diferentes que eu conheço para isso:
Em primeiro lugar, você pode passar ponteiros. É isso que a implementação do CPython faz. Todo objeto é um ponteiro PyObject
. Esses ponteiros são passados e as operações são executadas observando os detalhes na estrutura PyObject para descobrir o tipo.
A desvantagem é que valores pequenos, como números, são armazenados como valores em caixa. Assim, seu pequeno 5 é armazenado como um bloco de memória em algum lugar. Isso nos leva à abordagem de união, que é usada por Lua. Em vez de um PyObject*
, cada valor é uma estrutura que um campo para especificar o tipo e, em seguida, uma união de todos os diferentes tipos de suporte. Dessa forma, evitamos alocar memória para valores pequenos, em vez de armazená-los diretamente na união.
A abordagem NaN
armazena tudo como duplas e reutiliza a parte não utilizada de NaN
para o armazenamento extra. A vantagem sobre o método de união é que salvamos o campo type. Se é um duplo válido, é um duplo, caso contrário, a mantissa é um ponteiro para o objeto real.
Lembre-se, este é todo objeto javascript. Cada variável, todo valor em um objeto, toda expressão. Se pudermos reduzir todos aqueles de 96 bits para 64 bits, isso é bastante impressionante.
Vale a pena o hack? Lembre-se de que há muita demanda por JavaScript eficiente. Javascript é o gargalo em muitos aplicativos da Web e, portanto, torná-lo mais rápido é uma prioridade mais alta. É razoável introduzir um certo grau de imprevidência por motivos de desempenho. Para a maioria dos casos, seria uma má ideia, porque está introduzindo um grau de complexidade para pouco ganho. Mas, neste caso específico, vale a pena melhorar a memória e a velocidade.