| 1 | = Anonymous Methods/Closures and lambdas = |
| 2 | |
| 3 | Cobra supports both anonymous methods (also known as closures where they capture the values of surrounding variables if referenced) [[br]] |
| 4 | and a simpler single line expression form known as lambdas. |
| 5 | |
| 6 | Both are introduced with the "'''do'''" keyword. |
| 7 | |
| 8 | The syntax for closures is similar to that of the [wiki:Methods def] statement (defining a classes methods) |
| 9 | except that there is no method name. |
| 10 | |
| 11 | The body of the closure follows the line the '''do''' (plus any paramList) is on, indented one level |
| 12 | |
| 13 | A lambda uses the same "do" keyword as closures, but the argument list is followed by "=<expr>" all on a single line. |
| 14 | |
| 15 | |
| 16 | == Grammar == |
| 17 | Anonymous Method |
| 18 | {{{ |
| 19 | do [as <Type>] # no parameters |
| 20 | <body statements...> |
| 21 | |
| 22 | do(<paramList>) [as <Type>] |
| 23 | <body statements...> |
| 24 | |
| 25 | For these a parameter list is a comma separated list of name (and optionally type) specifications |
| 26 | <paramName> [as <Type>] [, ...] |
| 27 | }}} |
| 28 | |
| 29 | |
| 30 | Lambdas |
| 31 | {{{ |
| 32 | do = <expr> # no parameters |
| 33 | do (<paramList>) = <expr> # args passed as per invocation |
| 34 | }}} |
| 35 | |
| 36 | |
| 37 | == Examples == |
| 38 | Anonymous Method |
| 39 | {{{ |
| 40 | sig ArithmeticOp(a as int, b as int) as int |
| 41 | sig SimpleMethod |
| 42 | # ... |
| 43 | class Test |
| 44 | def callArithmeticOp(a as int, b as int, op as ArithmeticOp) as int |
| 45 | return op(a, b) |
| 46 | |
| 47 | def invoke(method as SimpleMethod) |
| 48 | method() |
| 49 | |
| 50 | #... |
| 51 | def run |
| 52 | assert 12 == .callArithmeticOp(3, 4, do(a as int, b as int)) |
| 53 | return a * b |
| 54 | |
| 55 | # multiple statements in the anonymous method |
| 56 | assert 12 == .callArithmeticOp(3, 4, do(a as int, b as int)) |
| 57 | r = 0 |
| 58 | for i in a |
| 59 | r += b |
| 60 | assert r == a * b |
| 61 | return r |
| 62 | |
| 63 | # access members |
| 64 | assert 24 == .callArithmeticOp(3, 4, do(a as int, b as int)) |
| 65 | return a * b * .two |
| 66 | |
| 67 | # access local vars |
| 68 | multiplier = 10 |
| 69 | assert 120 == .callArithmeticOp(3, 4, do(a as int, b as int)) |
| 70 | return a * b * multiplier |
| 71 | |
| 72 | count = 0 |
| 73 | .invoke(do) # no parameters |
| 74 | count += 1 |
| 75 | assert count == 1 |
| 76 | }}} |
| 77 | |
| 78 | Lambda |
| 79 | {{{ |
| 80 | t = [3, 2, 1] |
| 81 | t.sort(do(a as int, b as int)=a.compareTo(b)) |
| 82 | }}} |
| 83 | |
| 84 | == Notes == |
| 85 | |
| 86 | The argument types are not yet inferred which is why you should specify them explicitly typed |
| 87 | as in the examples above. |
| 88 | |
| 89 | Multiple closures on a single line are not yet supported. |
| 90 | |
| 91 | You can store a reference to a closure so long as you have a type for its signature. |
| 92 | e.g |
| 93 | {{{ |
| 94 | class Test |
| 95 | |
| 96 | def main is shared |
| 97 | t = [3, 2, 1] |
| 98 | |
| 99 | # embedded closure |
| 100 | t.sort(do(a as int, b as int)) |
| 101 | return a.compareTo(b) |
| 102 | |
| 103 | # store closure in local var |
| 104 | c as Comparison<of int> = do(a as int, b as int) |
| 105 | return a.compareTo(b) |
| 106 | t.sort(c) |
| 107 | }}} |