Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions docs/type-long-integer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# 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.


## Summary

A builtin type to represent 64-bit integers.

## Motivation

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.
Comment on lines +9 to +13
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.

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.


In both cases, performance is lacking compared to what could be provided by a native implementation.

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 and their use is widespread.

Specific use cases involve the implementation of specific algorithms (e.g. cryptography, FNV), timestamps, simpler integration with C libraries/runtimes including FFI, larger space for incremental identifiers, wider range of usable bits for libraries that currently are restricted to 2^53-1

While the above solutions, in addition to runtimes being able to define their own userdata do exist, requiring each runtime to reimplement 64 bit integer support with potentially different semantics could prove damaging to libraries that will have to find a common API between any supported runtime or use their own library to use something as simple as int64.

Representing 64-bit numbers as heap-allocated userdata is sufficient for correctness but adds a layer of indirection for something that can fit within the existing value size. In cases where the use of these numbers is more common, the performance characteristics of different implementations including userdata could be problematic.

Userdata remain the right mechanism for complex or embedder-specific numeric types but 64-bit integers have a sufficiently large problem domain to justify their inclusion as a core value type which may have benefits for performance wider interoperability in the overall ecosystem.

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.


## Design

This will be implemented a with new type called "long".

The long type will store a 64 bit integer.

An additional character may be specified at the end of numeric literals `L` which will signify an long integer literal.
Long integer literals will support separators, hex, and binary values.
Long integer literals should be parsed as an alternative to floating point values akin to the following regular expression `\d`.
Long integer literals should support scientific notation declarations e.g. `1e8L` and should produce an error if they result in a fractional part.

Longs will not coerce to a number or string, though type should include a __tostring.

Functions for creating/manipulating this type will exist in a new library called 'long`, which will have the following functions:

`long.tolong(n: number) -> long`

Converts a number to a long. Will throw an error if the value of the number exceeds the maximum integer, or if there is a fractional component to the number.

`long.fromstring(str: string, base: number?) -> long`

Converts a string representation of a number into a long in accordance with a specified base or base 10 if no argument is provided.

`long.tostring(n: long, b: base?) -> string`

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


Performs the associated operation on a long and another long. Functions prefixed with `u` operate over unsigned values where their normal counterparts assume signedness.
Operators for this type will not be implemented

`long.lshift`, `long.rshift`, `long.arshift`

Performs the associated bitwise operation on a long by a number.

`buffer.readlong(b: buffer, offset: number) -> long`

Reads a long out of a buffer at the given offset.

`buffer.writelong(b: buffer, offset: number, value: long)`

Writes a long to a buffer at the given offset.

### C API

`int64_t lua_tolong(lua_State *L, int index)`

Returns a long value on the stack at `index` if no value exists or if it is not a `long` then returns `0`.

`void lua_pushlong(lua_State *L, int64_t n)`

Pushes a long value of the specified signed to the stack

`int lua_islong(lua_State *L, int n)`

Determines if a value at index `n` is a long.

`int64_t luaL_checklong(lua_State *L, int index)`

Same behavior as `lua_tolong` and `lua_toulong` except errors if the value is not a long.

`luaopen_long(lua_State *L)`

Registers the `long` library. Included in `luaL_openlibs`

## Drawbacks

This increases the complexity of the VM as it may need to implement separate paths for mathematical operations.

## Alternatives

Do nothing, the workarounds exist and are in use but this will restrict the areas Luau can be used without implementation burden or reliance on an externally maintained implementation of 64-bit integers.