luau
luau copied to clipboard
Inaccuracies with "assert" return typing
Currently the assert function type is defined as
function assert(value: a, errorMessage: string?): a
when in actuality assert returns a tuple, thus it should be some variant of
function assert(value: a, errorMessage: string?): (a, ...)
Under most circumstances this is fine, however recently it caused some headaches when I tried asserting a value directly into a table, leading to the second return variable, the error message itself, being added to the table.
The problem is that assert
only returns an error message if one is provided, so the most accurate return type would have to have either a constrained generic (which we don't have in luau yet) or an overloaded function, which would look something like this:
type assert = (<a>(value: a) -> (a)) & (<a>(value: a, errorMessage: string) -> (a, string))
(I'm also unsure why you included a variadic return type? Does assert
ever return more than 2 values or was it just a placeholder?)
Makes sense! I didn't really understand the underlying mechanism, so I didn't want to assume too much hence the (a, ...)
, your type definition is certainly better and should be used.
The problem is that
assert
only returns an error message if one is provided, so the most accurate return type would have to have either a constrained generic (which we don't have in luau yet) or an overloaded function, which would look something like this:type assert = (<a>(value: a) -> (a)) & (<a>(value: a, errorMessage: string) -> (a, string))
Actually, assert
has a rather weird, and undocumented, behaviour. errorMessage
can be any object (in fact, it is variadic) as long as value
is truthy, but same argument can only be string
or number
otherwise (for some reason), and it only prints the first value passed to errorMessage
.
Therefore, the more accurate type annotation would be like this:
type assert = ((value: false?, errorMessage: (string | number)?) -> never)
& (<V, A...>(value: V, A...) -> (V, A...))
Interesting, is it possible that the usage of non-strings is deprecated? If not then a second variadic type would certainly be the best way to type it.
Interesting, is it possible that the usage of non-strings is deprecated?
This implies that this behaviour was documented at some point, but a quick check of the official documentation for different versions of Lua reveals that it was never documented in the first place ever since the function was added back in Lua 2.4.
Therefore, the more accurate type annotation would be like this:
type assert = ((value: false?, errorMessage: (string | number)?) -> never) & (<V, A...>(value: V, A...) -> (V, A...))
I think it would be best to use the first annotation since this would just be confusing to newcomers. I doubt anyone in the history of Lua has actually used this behavior, and it would be best to keep it that way.