v1.0.1-SNAPSHOT: named args in calls
This commit is contained in:
1 parent
d6e6d68b18
commit
2d721101dd
14 files changed
+695
-170
No files matched your search
@@ -0,0 +1,80 @@
|
||||
Note for AI. please ignore this file until this remark is removed.
|
||||
|
||||
# Map literals proposal
|
||||
|
||||
Note to the AI: please ignore this file until this note is removed.
|
||||
|
||||
Implement javascript-like literals for maps. It uses the similar syntax already adopted for named arguments in function calls so it should be organic and familiar, as the purpose is similar.
|
||||
|
||||
String literal keys
|
||||
|
||||
```lyng
|
||||
val m = { a: "foo", b: "bar" }
|
||||
assertEqual(m.a, "foo")
|
||||
assertEqual(m.b, "bar")
|
||||
```
|
||||
|
||||
The map literal is a map with keys that are string literals only. This is important. In a relatively rare case when keys are calculated, or extravagant but still possible case when keys are of different types, literal could be combined with "=>":
|
||||
|
||||
```lyng
|
||||
val k1 = "bar"
|
||||
val m = { "foo": 123 } + k1 => "buzz"
|
||||
// this is same as Map("foo" => 123) + Map("bar" => k2) but can be optimized by compiler
|
||||
assertEqual(m["foo"], 123)
|
||||
assertEqual(m["bar"], "buzz")
|
||||
```
|
||||
|
||||
The lambda syntax is different, it can start with the `map_lteral_start` above, it should produce compile time error, so we can add map literals of this sort.
|
||||
|
||||
Also, we will allow splats in map literals:
|
||||
|
||||
```
|
||||
val m = { foo: "bar", ...{bar: "buzz"} }
|
||||
assertEquals("bar",m["foo"])
|
||||
assertEquals("buzz", m["bar"])
|
||||
```
|
||||
|
||||
When the literal argument and splats are used together, they must be evaluated left-to-right with allowed overwriting
|
||||
between named elements and splats, allowing any combination and multiple splats:
|
||||
|
||||
```
|
||||
val m = { foo: "bar", ...{bar: "buzz"}, ...{foo: "foobar"}, bar: "bar" }
|
||||
assertEquals("foobar",m["foo"])
|
||||
assertEquals("bar", m["bar"])
|
||||
```
|
||||
|
||||
Still we disallow duplicating _string literals_:
|
||||
|
||||
```
|
||||
// this is an compile-time exception:
|
||||
{ foo: 1, bar: 2, foo: 3 }
|
||||
```
|
||||
|
||||
Special syntax allows to insert key-value pair from the variable which name should be the key, and content is value:
|
||||
|
||||
```
|
||||
val foo = "bar"
|
||||
val bar = "buzz"
|
||||
assertEquals( {foo: "bar", bar: "buzz"}, { foo, bar } )
|
||||
```
|
||||
|
||||
|
||||
So, summarizing, overwriting/duplication rules are:
|
||||
|
||||
- string literals can't duplicate
|
||||
- splats add or update content, effectively overwrite preceding content,
|
||||
- string literals overwrite content received from preceding splats (as no duplication string literal keys allowed)
|
||||
- the priority and order is left-to-right, rightmost wins.
|
||||
- var inclusion is treated as form of the literal
|
||||
|
||||
This approach resolves the ambiguity from lambda syntax, as
|
||||
|
||||
```ebnf
|
||||
ws = zero or more whitespace characters including newline
|
||||
map_literal start = "{", ws, (s1 | s2 | s3)
|
||||
s1 = string_literal, ws, ":", ws, expression
|
||||
s2 = "...", string_literal
|
||||
s3 = string_literal, ("," | "}")
|
||||
```
|
||||
is not a valid lambda beginning.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# Named arguments proposal
|
||||
|
||||
Extend function/method calls to allow setting arguments by name using colon syntax at call sites. This is especially convenient with many parameters and default values.
|
||||
|
||||
Examples:
|
||||
|
||||
```lyng
|
||||
fun test(a="foo", b="bar", c="bazz") { [a, b, c] }
|
||||
|
||||
assertEquals(test(b: "b"), ["foo", "b", "bazz"])
|
||||
assertEquals(test("a", c: "c"), ["a", "bar", "c"])
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Named arguments are optional. If named arguments are present, their order is not important.
|
||||
- Named arguments must follow positional arguments; positional arguments cannot follow named ones (the only exception is the syntactic trailing block outside parentheses, see below).
|
||||
- A named argument cannot reassign a parameter already set positionally.
|
||||
- If the last parameter is already assigned by a named argument (or named splat), the trailing-lambda rule must NOT apply: a following `{ ... }` after the call is an error.
|
||||
|
||||
Rationale for using `:` instead of `=` in calls: in Lyng, assignment `=` is an expression; using `:` avoids ambiguity and keeps declarations (`name: Type`) distinct from call sites, where casting uses `as` / `as?`.
|
||||
|
||||
Migration note: earlier drafts/examples used `name = value`. The final syntax is `name: value` at call sites.
|
||||
|
||||
## Extended call argument splats: named splats
|
||||
|
||||
With named arguments, splats (`...`) are extended to support maps as named splats. When a splat evaluates to a Map, its entries provide name→value assignments:
|
||||
|
||||
```lyng
|
||||
fun test(a="a", b="b", c="c", d="d") { [a, b, c, d] }
|
||||
|
||||
assertEquals(test("A?", ...Map("d" => "D!", "b" => "B!")), ["A?", "B!", "c", "D!"])
|
||||
```
|
||||
|
||||
Constraints for named splats:
|
||||
|
||||
- Only string keys are allowed in map splats; otherwise, a clean error is thrown.
|
||||
- Named splats cannot reassign parameters already set (positionally or by earlier named arguments/splats).
|
||||
- Named splats follow the same ordering as named arguments: they must appear after all positional arguments and positional splats.
|
||||
|
||||
## Trailing-lambda interaction
|
||||
|
||||
Lyng supports a syntactic trailing block after a call: `f(args) { ... }`. With named args/splats, if the last parameter is already assigned by name, the trailing block must not apply and the call is an error:
|
||||
|
||||
```lyng
|
||||
fun f(x, onDone) { onDone(x) }
|
||||
f(x: 1) { 42 } // ERROR: last parameter already assigned by name
|
||||
f(1) { 42 } // OK
|
||||
```
|
||||
|
||||
## Errors (non-exhaustive)
|
||||
|
||||
- Positional argument after any named argument inside parentheses: error.
|
||||
- Positional splat after any named argument: error.
|
||||
- Duplicate named assignment (directly or via map splats): error.
|
||||
- Unknown parameter name in a named argument/splat: error.
|
||||
- Map splat with non-string keys: error.
|
||||
- Attempt to target the ellipsis parameter by name: error.
|
||||
|
||||
## Notes
|
||||
|
||||
- Declarations continue to use `:` for types, while call sites use `:` for named arguments and `as` / `as?` for type casts/checks.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user