Mercerenies / gdlisp

Lisp on the Godot platform
GNU General Public License v3.0
140 stars 1 forks source link

Keyword/Named Arguments #55

Open Mercerenies opened 2 years ago

Mercerenies commented 2 years ago

Many languages (Common Lisp, Python, Ruby, Julia) support named arguments. That is, we can designate particular arguments by name and then call the function with those arguments designated, again, by name.

I propose syntax something like this (this exact call syntax will not work; see below for details)

(defn foo (positional &key keyword1 keyword2))

and it can be called as

;; These two are equivalent
(foo "A" keyword1: "B" keyword2: "C")
(foo "A" keyword2: "C" keyword1: "B")

We can also accept "extra" keyword arguments as a dictionary with &dict or something similar (should we also support association-lists as &kwargs or something, for consistency with the &rest / &arr dichotomy?). Every call_funcv will now take two mandatory arguments: one positional list of arguments and one dictionary of keyword arguments. This will complicated call_funcv quite a bit, unfortunately.

Syntax Issues

We can't use the :keyword1 Common Lisp style syntax or keyword1: since : is used in GDLisp for accessing instance fields/methods. Consider other syntactic forms.

Compiling

For anything in the function namespace, these will get parsed and compiled at compile-time with no overhead. For funcrefs and lambdas, we'll have to factor through funcall, which is a bit more intensive. As mentioned above, call_funcv is about to get a lot more complicated.

As with most other lambda list features, keyword arguments are forbidden in instance methods and inner class static methods.

Positional vs. Keyword Arguments

Some languages such as Python and Kotlin default to allowing arguments to be either positional or keyword. In Python, there is a mechanism for specifying that an argument may only be passed one way. Other languages, like Ruby and Julia, demand that you specify a particular calling mechanism for each argument in advance. We're likely to favor the latter approach, for simplicity and consistency. I expect users to generally use positional arguments in most cases, and certainly in any cases where a function is likely to be treated as a callback, and then we use keyword arguments in other cases where we need to take several arguments which don't have a natural order to them. Keyword arguments should be the minority of use cases, though.