<p>What are some ways that existing programming languages handle function definitions, and what are the pros and cons of each method? By &quot;function definitions&quot; I mean either named (i.e. <code>function foo(a, b) { return a + b; }</code> in JavaScript) or anonymous (lambda) functions (i.e. <code>(a, b) =&gt; a + b</code> in JS). I'm not looking for special kinds of functions (e.g. asynchronous, generator, etc. where definition syntax might be different) but general ones.</p>
<p>I'm looking for answers in terms of readability, familiarity, verbosity, and any other advantages/disadvantages that may come with different syntaxes.</p>

<syntax><functions>
What are some options for function definition syntax?
<h1>ML Style:</h1>
<pre><code>let add x y = x + y

let apply_as_tuple f a b = f (a, b)
</code></pre>
<h1>Pros:</h1>
<ul>
<li>Looks the same as the value syntax, enforcing functions-are-values</li>
<li>Works with automatic currying</li>
<li>Fairly simple</li>
</ul>
<h1>Cons:</h1>
<ul>
<li>Requires a keyword (let)</li>
<li>Doesn't look as good with non-curried arguments</li>
<li>Enforces whitespace function call syntax, which may not be ideal</li>
</ul>

CC BY-SA 4.0
2023-05-17T04:32:34.313Z
2023-05-17T04:32:34.313Z
blueberry
<p>Lambda functions with simple arrow (=&gt; or -&gt;) syntax is necessary for implementing of chained streaming API:</p>
<p><code>map</code> <code>filter</code> <code>takeWhile</code> <code>dropWhile</code> <code>reduce</code>, etc.</p>
<p>See how ugly it is in <code>Go</code>:</p>
<pre><code>even := lo.Filter([]int{1, 2, 3, 4}, func(x int, index int) bool {
    return x % 2 == 0
})
// []int{2, 4}
</code></pre>
<p>And in <code>Java</code>:</p>
<pre><code>int[] a = {1, 2, 3, 4};
int[] even = Arrays.stream(a)
    .filter(i -&gt; i % 2 == 0)
    .toArray();
</code></pre>

CC BY-SA 4.0
2023-05-17T06:26:11.190Z
2023-05-17T06:27:06.367Z
2023-05-17T06:27:06.367Z
wolray
CC BY-SA 4.0
2023-05-18T14:10:08.397Z
Yes, and Kotlin can also do that by a scope variable called `it`.  I just simply hate the Go-style lambdas.
wolray
CC BY-SA 4.0
2023-05-18T14:34:01.877Z
Even when you write it out in full, Swift uses `in` rather than Kotlin’s arrow.
Bbrk24
CC BY-SA 4.0
2023-05-17T10:51:16.700Z
Swift has this without arrow functions _per se_; that filter call would be `.filter { $0.isMultiple(of: 2) }`.
Bbrk24
<p>I think overloading would be really difficult when assigning a lambda. I can't even conceive of how this would be done:</p>
<pre><code>foo = (x) =&gt; x + 1
foo = (x, y) =&gt; x + y
</code></pre>
<p>Whereas syntax for explicitly declaring a function makes overloading a breeze:</p>
<pre><code>func foo(x): return x + 1
func foo(x, y): return x + y
</code></pre>
<p>The first case makes me think it would be pretty difficult for the compiler to distinguish that the second assignment is an overload as opposed to a mutation or redeclaration of the <code>foo</code> variable.</p>

CC BY-SA 4.0
2023-05-17T01:42:13.870Z
2023-05-17T01:42:13.870Z
chrisaycock
CC BY-SA 4.0
2023-08-11T16:20:05.603Z
Well, perhaps overloading can be supported simply replacing `name = ...` by `name += ...`. [Yeah, it entangles name lookup with order of evaluation... :-( ] [Comment repeated from another answer.]
Pablo H
CC BY-SA 4.0
2023-05-17T01:52:18.953Z
Thats why you *dont* overload with these kinds of functions
Seggan
CC BY-SA 4.0
2023-05-17T04:48:11.757Z
You could do something like `let f = { (x) => x + 1, (x,y) => x + y}` like you would do in math
mousetail 'he-him'
<h1>Functions should be a special case of lambdas</h1>
<p>For example:</p>
<pre><code>// lambda
(args) =&gt; code

// function

name = (args) =&gt; code
</code></pre>
<p>In this way, named functions become variables that have been assigned a function object.</p>
<h2>Pros</h2>
<ul>
<li>Only one syntax structure is needed for lambdas and functions, meaning the language is easier to learn and more orthogonal.</li>
<li>In a language that treats functions as first-class citizens, this drives home the idea that functions are objects that can be passed around just like any other value.</li>
<li>The named function syntax becomes more analogous to mathematics, where you would write <code>f(x) = some expression</code></li>
</ul>
<h2>Cons</h2>
<ul>
<li>In a language where functions aren't first-class citizens, this doesn't make as much sense, and might not even be supported if you don't have lambdas.</li>
<li>It can be less clear what is a procedure and what isn't.</li>
<li>Multiline function bodies would need to be expressions to fit with the lambda model, meaning you would need to rework your language design to fit around that.</li>
<li>Overloads are made impossible.</li>
</ul>

CC BY-SA 4.0
2023-05-17T00:46:28.160Z
2023-05-17T01:53:08.030Z
2023-05-17T01:53:08.030Z
lyxal
CC BY-SA 4.0
2023-05-17T01:31:03.843Z
This is how CoffeeScript does it -- all functions are arrow functions -- which threw me off at first, since I'd never seen it before.
Bbrk24
CC BY-SA 4.0
2023-05-17T01:51:34.673Z
Lua does that too
Seggan
CC BY-SA 4.0
2023-05-17T04:39:30.043Z
Overloads could be supported using a magic stdlib function or a bit of syntax, say, `name = overload((a: int) => a + 1, (a: string) => a[0])`
RubenVerg
CC BY-SA 4.0
2023-05-17T07:41:22.477Z
I find this a too opinionated answer. There is no strict need for them to be the same. It is desirable yes, but there are other considerations that are more important.
Nuoji
CC BY-SA 4.0
2023-05-17T07:47:33.433Z
@Nuoji that's why it's an answer that gives the pros and cons of the approach - it's an opinion with both sides considered
lyxal
CC BY-SA 4.0
2023-08-11T16:15:12.813Z
Well, perhaps overloading can be supported simply replacing `name = ...` by `name += ...`. [Yeah, it entangles name lookup with order of evaluation... :-( ]
Pablo H
CC BY-SA 4.0
2023-08-11T23:09:17.760Z
@PabloH that is an interesting suggestion, never thought of that one before. Order of evaluation could be avoided by treating `function +=` as a special case (determinable through something like static typing).
lyxal
<p>The possible choices for function syntax depends very much on the variable and constant declaration syntax.</p>
<p>If anonymous functions / lambdas are needed, they need to be constructed exactly in a way that grammar ambiguities are avoided, and obviously this depends on the overall grammar.</p>
<p>In the lambda case, many languages also offer shorter forms with types inferred. As lambdas as often used as callbacks or computation functions, this often increases readability for short functions.</p>
<p>An overview of different syntax I often use is <a href="http://rigaux.org/language-study/syntax-across-languages/Fnctn.html" rel="nofollow noreferrer">this</a>.</p>
<p>There are no clear cut rules, while one would prefer function and lambda follow each other closely, there can be trade-offs with other concerns such as the overall grammar complexity, readability etc.</p>
<p>Some examples:</p>
<p>C++ (note how the capture list with <code>[]</code> also serves to disambiguate the grammar somewhat)</p>
<pre class="lang-c prettyprint-override"><code>int foo(int a) { ... }
x = [](int a) -&gt; int { ... };
</code></pre>
<p>Ruby (syntax is different from function construction, but consistent with other constructs using blocks)</p>
<pre class="lang-ruby prettyprint-override"><code>def foo(a) ... end
x = lambda { |a| ... }
</code></pre>
<p>Go (function and lambda declarations are very similar)</p>
<pre class="lang-go prettyprint-override"><code>func foo(a int) int { ... }
x = func(a int) int { ... }
</code></pre>
<p>Java (note the special short syntax available for lambdas)</p>
<pre class="lang-java prettyprint-override"><code>int foo(int a) { ... }
x = a -&gt; { ... }
</code></pre>
<p>Swift (similar to Java it has special inferred forms available for lambdas)</p>
<pre class="lang-swift prettyprint-override"><code>func foo(a: Int32) -&gt; Int32 { ... }
y = { a in ... }
</code></pre>

CC BY-SA 4.0
2023-05-17T07:40:13.873Z
2023-05-19T19:02:06.403Z
2023-05-19T19:02:06.403Z
Nuoji
CC BY-SA 4.0
2023-05-17T08:08:47.787Z
Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer).
Community Compiler
# What are some options for function definition syntax?
Posted by: username_0 on 2023-05-16
What are some ways that existing programming languages handle function definitions, and what are the pros and cons of each method? By "function definitions" I mean either named (i.e. `function foo(a, b) { return a + b; }` in JavaScript) or anonymous (lambda) functions (i.e. `(a, b) => a + b` in JS). I'm not looking for special kinds of functions (e.g. asynchronous, generator, etc. where definition syntax might be different) but general ones.

I'm looking for answers in terms of readability, familiarity, verbosity, and any other advantages/disadvantages that may come with different syntaxes.
**Tags:** syntax functions
---
## 5 answers
### Answer by username_8 on 2023-05-17. Score: 7
Functions should be a special case of lambdas
For example:
// lambda
(args) => code

// function

name = (args) => code

In this way, named functions become variables that have been assigned a function object.
Pros

Only one syntax structure is needed for lambdas and functions, meaning the language is easier to learn and more orthogonal.
In a language that treats functions as first-class citizens, this drives home the idea that functions are objects that can be passed around just like any other value.
The named function syntax becomes more analogous to mathematics, where you would write f(x) = some expression

Cons

In a language where functions aren't first-class citizens, this doesn't make as much sense, and might not even be supported if you don't have lambdas.
It can be less clear what is a procedure and what isn't.
Multiline function bodies would need to be expressions to fit with the lambda model, meaning you would need to rework your language design to fit around that.
Overloads are made impossible.
> **Comments:**
> **username_3** (2023-05-17): This is how CoffeeScript does it -- all functions are arrow functions -- which threw me off at first, since I'd never seen it before.  
> **username_6** (2023-05-17): Lua does that too  
> **username_9** (2023-05-17): Overloads could be supported using a magic stdlib function or a bit of syntax, say, `name = overload((a: int) => a + 1, (a: string) => a[0])`  
> **username_10** (2023-05-17): I find this a too opinionated answer. There is no strict need for them to be the same. It is desirable yes, but there are other considerations that are more important.  
> **username_8** (2023-05-17): @Nuoji that's why it's an answer that gives the pros and cons of the approach - it's an opinion with both sides considered  
> **username_5** (2023-08-11): Well, perhaps overloading can be supported simply replacing `name = ...` by `name += ...`. [Yeah, it entangles name lookup with order of evaluation... :-( ]  
> **username_8** (2023-08-11): @PabloH that is an interesting suggestion, never thought of that one before. Order of evaluation could be avoided by treating `function +=` as a special case (determinable through something like static typing).  
---
### Answer by username_10 on 2023-05-17. Score: 4
The possible choices for function syntax depends very much on the variable and constant declaration syntax.
If anonymous functions / lambdas are needed, they need to be constructed exactly in a way that grammar ambiguities are avoided, and obviously this depends on the overall grammar.
In the lambda case, many languages also offer shorter forms with types inferred. As lambdas as often used as callbacks or computation functions, this often increases readability for short functions.
An overview of different syntax I often use is this.
There are no clear cut rules, while one would prefer function and lambda follow each other closely, there can be trade-offs with other concerns such as the overall grammar complexity, readability etc.
Some examples:
C++ (note how the capture list with [] also serves to disambiguate the grammar somewhat)
int foo(int a) { ... }
x = [](int a) -> int { ... };

Ruby (syntax is different from function construction, but consistent with other constructs using blocks)
def foo(a) ... end
x = lambda { |a| ... }

Go (function and lambda declarations are very similar)
func foo(a int) int { ... }
x = func(a int) int { ... }

Java (note the special short syntax available for lambdas)
int foo(int a) { ... }
x = a -> { ... }

Swift (similar to Java it has special inferred forms available for lambdas)
func foo(a: Int32) -> Int32 { ... }
y = { a in ... }
> **Comments:**
> **username_11** (2023-05-17): Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer).  
---
### Answer by username_1 on 2023-05-17. Score: 3
ML Style:
let add x y = x + y

let apply_as_tuple f a b = f (a, b)

Pros:

Looks the same as the value syntax, enforcing functions-are-values
Works with automatic currying
Fairly simple

Cons:

Requires a keyword (let)
Doesn't look as good with non-curried arguments
Enforces whitespace function call syntax, which may not be ideal
---
### Answer by username_4 on 2023-05-17. Score: 3
I think overloading would be really difficult when assigning a lambda. I can't even conceive of how this would be done:
foo = (x) => x + 1
foo = (x, y) => x + y

Whereas syntax for explicitly declaring a function makes overloading a breeze:
func foo(x): return x + 1
func foo(x, y): return x + y

The first case makes me think it would be pretty difficult for the compiler to distinguish that the second assignment is an overload as opposed to a mutation or redeclaration of the foo variable.
> **Comments:**
> **username_6** (2023-05-17): Thats why you *dont* overload with these kinds of functions  
> **username_7** (2023-05-17): You could do something like `let f = { (x) => x + 1, (x,y) => x + y}` like you would do in math  
> **username_5** (2023-08-11): Well, perhaps overloading can be supported simply replacing `name = ...` by `name += ...`. [Yeah, it entangles name lookup with order of evaluation... :-( ] [Comment repeated from another answer.]  
---
### Answer by username_2 on 2023-05-17. Score: 1
Lambda functions with simple arrow (=> or ->) syntax is necessary for implementing of chained streaming API:
map filter takeWhile dropWhile reduce, etc.
See how ugly it is in Go:
even := lo.Filter([]int{1, 2, 3, 4}, func(x int, index int) bool {
    return x % 2 == 0
})
// []int{2, 4}

And in Java:
int[] a = {1, 2, 3, 4};
int[] even = Arrays.stream(a)
    .filter(i -> i % 2 == 0)
    .toArray();
> **Comments:**
> **username_3** (2023-05-17): Swift has this without arrow functions _per se_; that filter call would be `.filter { $0.isMultiple(of: 2) }`.  
> **username_2** (2023-05-18): Yes, and Kotlin can also do that by a scope variable called `it`.  I just simply hate the Go-style lambdas.  
> **username_3** (2023-05-18): Even when you write it out in full, Swift uses `in` rather than Kotlin’s arrow.  
---
