mirror of
https://github.com/luau-lang/luau.git
synced 2024-12-13 05:20:38 +00:00
67 lines
2.1 KiB
Markdown
67 lines
2.1 KiB
Markdown
|
# Type ascriptions
|
||
|
|
||
|
> Note: this RFC was adapted from an internal proposal that predates RFC process
|
||
|
|
||
|
## Summary
|
||
|
|
||
|
Implement syntax for type ascriptions using `::`
|
||
|
|
||
|
## Motivation
|
||
|
|
||
|
Luau would like to provide a mechanism for requiring a value to be of a specific type:
|
||
|
|
||
|
```
|
||
|
-- Asserts that the result of a + b is a number.
|
||
|
-- Emits a type error if it isn't.
|
||
|
local foo = (a + b) as number
|
||
|
```
|
||
|
|
||
|
This syntax was proposed in the original Luau syntax proposal. Unfortunately, we discovered that there is a syntactical ambiguity with `as`:
|
||
|
|
||
|
```
|
||
|
-- Two function calls or a type assertion?
|
||
|
foo() as (bar)
|
||
|
```
|
||
|
|
||
|
## Design
|
||
|
|
||
|
To provide this functionality without introducing syntactical confusion, we want to change this syntax to use the `::` symbol instead of `as`:
|
||
|
|
||
|
```
|
||
|
local foo = (a + b) :: number
|
||
|
```
|
||
|
|
||
|
This syntax is borrowed from Haskell, where it performs the same function.
|
||
|
|
||
|
The `::` operator will bind very tightly, like `as`:
|
||
|
|
||
|
```
|
||
|
-- type assertion applies to c, not (b + c).
|
||
|
local a = b + c :: number
|
||
|
```
|
||
|
|
||
|
Note that `::` can only cast a *single* value to a type - not a type pack (multiple values). This means that in the following context, `::` changes runtime behavior:
|
||
|
|
||
|
```
|
||
|
foo(1, bar()) -- passes all values returned by bar() to foo()
|
||
|
foo(1, bar() :: any) -- passes just the first value returned by bar() to foo()
|
||
|
```
|
||
|
|
||
|
## Drawbacks
|
||
|
|
||
|
It's somewhat unusual for Lua to use symbols as operators, with the exception of arithmetics (and `..`). Also a lot of Luau users may be familiar with TypeScript, where the equivalent concept uses `as`.
|
||
|
|
||
|
`::` may make it more difficult for us to use Turbofish (`::<>`) in the future.
|
||
|
|
||
|
## Alternatives
|
||
|
|
||
|
We considered requiring `as` to be wrapped in parentheses, and then relaxing this restriction where there's no chance of syntactical ambiguity:
|
||
|
|
||
|
```
|
||
|
local foo: SomeType = (fn() as SomeType)
|
||
|
-- Parentheses not needed: unambiguous!
|
||
|
bar(foo as number)
|
||
|
```
|
||
|
|
||
|
We decided to not go with this due to concerns about the complexity of the grammar - it requires users to internalize knowledge of our parser to know when they need to surround an `as` expression with parentheses. The rules for when you can leave the parentheses out are somewhat nonintuitive.
|