Skip to content

Conversation

@bjcscat
Copy link

@bjcscat bjcscat commented Nov 30, 2025

@bjcscat bjcscat marked this pull request as draft November 30, 2025 09:52
Comment on lines +9 to +13
Current methods of representing 64-bit integers in Luau are done with high-low pairs or by splitting them among vectors which leads to poor ergonomics and may not be sufficient for cases where performance is important.

In the case of a high-low pair implementation each individual number takes 16 bytes (or 24) and needs to be be handled together which can be confusing.

In the case of vector implementations, ergonomics are improved by storing the entire integer in one value however you have the same issues of implementation complexity and lack of integration with the type system.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think 'what some people do' is actually a good motivation for a value type.
Motivation should come from problems that are being solved.

People can just do a custom userdata type like it was done in Lua 5.1 modules and have the right ergonomics.
Breaking apart in vector bits is only a 'trick' that you are not required to follow.


In the case of a high-low pair implementation each individual number takes 16 bytes (or 24) and needs to be be handled together which can be confusing.

In the case of vector implementations, ergonomics are improved by storing the entire integer in one value however you have the same issues of implementation complexity and lack of integration with the type system.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom userdata can also integrate into the type system, no one is forced to use the trick with worse ergonomics.

Comment on lines 17 to 18
As Luau grows the restriction to doubles will be an increasing pain point for any use case which involves a 64-bit integer.
System support for 64-bit integers is ubiquitous their use is widespread.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no restriction currently as an embedder can have custom userdata types.
Even out conformance tests implement an int64 type for userdata testing.

As Luau grows the restriction to doubles will be an increasing pain point for any use case which involves a 64-bit integer.
System support for 64-bit integers is ubiquitous their use is widespread.

While a runtime could implement 64-bit integers with userdata, performing an allocation for each integer (which can easily fit within an existing Luau value) is an onerous requirement.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not an onerous requirement in a language like Luau.
Userdata path is a completely normal way to implement custom types for the embedder.
Languages similar to Luau also take the same boxed garbage-collectable object paths in their implementation and Luau has an efficient allocator to support this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the section here in favor of other ones. The intent is not to say userdata are inappropriate or insufficient in general, but that for the specific case of simple 64-bit integer, a value type representation will have better performance characteristic than a boxed implementation can reasonably provide.

System support for 64-bit integers is ubiquitous their use is widespread.

While a runtime could implement 64-bit integers with userdata, performing an allocation for each integer (which can easily fit within an existing Luau value) is an onerous requirement.
A lightuserdata could avoid this allocation this but implementers will not be able to use operators or have any integration with the type system.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedders should use userdata and for many motivating cases of this type (none of which are included in this RFC btw) it works perfectly well.

While a runtime could implement 64-bit integers with userdata, performing an allocation for each integer (which can easily fit within an existing Luau value) is an onerous requirement.
A lightuserdata could avoid this allocation this but implementers will not be able to use operators or have any integration with the type system.

Most other high-level language have builtin support for 64-bit integers, including Lua since 5.3.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many don't or have the same solution as a userdata already solves so arguably it is already included in Luau.

Luau aims for a small core that is extendable and embedders built on it and bring in their own types as they need.
We don't have to have everything implemented in core.

Having an int64 type can be simple enough and useful, so I can see it in Luau, just finding the motivation really lacking in this RFC in particular.

@@ -0,0 +1,96 @@
# Long Integer Type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we will go with this name if this goes forward.
What is 'long' and why it is 64 bit.
We don't even have an integer type to have a 'long' counterpart and by itself it stands to confuse.

@gaymeowing
Copy link
Contributor

I think calling the library int or integer would be a much better fit than long, or alternatively bit64 as there is some presidence here with coroutine.create() not returning a coroutine but a thread so bit64.create() would return an integer or whatever name for the type is decided.


Converts a long to a string representation with the given base.

`long.add`, `long.sub`, `long.mul`, `long.div`, `long.mod`, `long.udiv`, `long.umod`, `long.band`, `long.bor`, `long.xor`, `long.lt`, `long.le`, `long.ult`
Copy link
Contributor

@gaymeowing gaymeowing Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not allow for using metamethods like how vector does? Is there any runtime implications here that I'm unfamiliar with?
Even then I feel like those runtime issues could be overcome by having a third optimization level that removes loadstring and get/set fenv, with this third optimization level being a thing until luau is ready to just flat out remove loadstring and get/set fenv.

Roblox could also then add a property to workspace for using optimization level 3 in-game rather than level 2.
Having a third optimization level has been an idea thats been on my mind for awhile now, and I think it'd be a good way to start a push for finally removing loadstring and get/set fenv. As people would be able to see the performance improvements directly, rather than just having the loose idea of improved performance.
Would also be a lot better than just having a random devforum announcement out of nowhere one day saying you have 6 months to remove get/set fenv and loadstring from your game.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the result of an ultimatum given to me in the ROSS discord saying that an RFC with operators will not go forward

@zoon
Copy link

zoon commented Dec 2, 2025

I would like to make a suggestion for the motivational section:

Benchmarks show a significant performance gap between heap-allocated userdata and value types. A simple addition loop with -O2 optimization yields the following results:

Implementation Time per Op Relative Speed
Native number ~3.0 ns 1x (Baseline)
Native vector ~5.0 ns ~1.7x slower
Userdata int64 ~60.0 ns ~20x slower

The userdata approach is significantly slower primarily due to allocation overhead and pointer indirection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants