-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Function default arguments #91
base: master
Are you sure you want to change the base?
RFC: Function default arguments #91
Conversation
f2edf59
to
8d84199
Compare
8d84199
to
a693fcf
Compare
### Language implementation | ||
Within the AST, it would likely be simpler to add a new `AstArray<AstExpr*> argsDefaults` to `AstExprFunction` alongside `args`, rather than modify `args` to be an `std::pair` due to the existing widespread usage of `args`. | ||
|
||
Rather than implement this as a feature of the `CALL` instruction within Luau's VM it is instead suggested by this RFC to implement this as part of the compiler. This both increases compatibility (as the VM remains unchanged) and makes it easier to allow *any* expression to be used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So does this mean function f(x: number = 3)
means that I call f()
and it compiles as f(3)
?
What happens then if I use that function as a first class value?
What happens then in this case?
local function g(callback: (number) -> ())
callback()
end
g(f)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ask because surely something with default parameters cannot have a non-optional argument as part of its type and also be a first class value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The suggested implementation essentially injects a series of if x == nil then x = default end
statements at the start of the function body, so passing f
around as a first class value is totally fine. If we run
-- !strict
function f(x: number = 3)
print(x)
end
local function g(callback: (number) -> ())
callback()
end
g(f)
we get 3
on stdout as expected.
We do however get a type error of TypeError: Argument count mismatch. Function 'callback' expects 1 argument, but none are specified
because the first class value f
will have a type of (number?) -> ...any
as defined there (to indicate that we need not provide that argument/could provide nil
).
Amending g to local function g(callback: (number?) -> ())
that type error goes away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a section that hopefully formalises that brief explanation into the RFC. lmk if there's still confusion (or another type interaction I've not formalised!).
What is the behavior of the upvalue references in the default value expressions? Do they act like any other upvalue reference from within the body? For example: local x = "foo"
local function getX(arg = x)
return arg
end
print(getX()) --> foo
x = "bar"
print(getX()) --> foo or bar? |
It would be |
Rendered
This RFC proposes adding default argument values, removing the need for
if arg == nil then arg = default end
cases at the start of every function.TL;DR
along with all of the semantics and type inference you might expect from that example.
I have a working implementation of this feature on my luau fork. The brave adventurer may wish to run a build and play around but otherwise this serves more to show that this could be reasonably add into the language with minimal work required.