Bits of Syntax: Function Application
Tags: discuss, design, healthydebate, watercooler
Published: 2019-10-28 11:16:34

## Parentheticals

After variable assignment, function application is probably the most fundamental aspect of any programming language's API.

[Many](https://www.tutorialspoint.com/cprogramming/c_functions.htm), [many](https://www.pitt.edu/~naraehan/python2/user_defined_functions.html), [many](https://codeburst.io/javascript-functions-understanding-the-basics-207dbf42ed99) programming languages use parentheses `()` to indicate function application:

```python
print("this is a string")
```

In the above case, `"this is a string"` is an _argument_ (or a _parameter_) that's _passed to_ the function `print()`. (In fact, functions are often written in text with `()` after them to indicate that they are functions and not variables or some other kind of construct.) In these languages which use `()` to indicate a list of parameters, functions with no parameters often still need the `()` following the function name to indicate the function call:

```r
cat()
```

In the R language, for instance, calling a zero-argument function with `()` appended will execute the function, while calling it without a trailing `()` will return some meta-information about the function itself, including (sometimes) its implementation:

```R
> cat()
> cat
function (..., file = "", sep = " ", fill = FALSE, labels = NULL, 
    append = FALSE) 
{
    if (is.character(file)) 
        if (file == "") 
            file <- stdout()
        else if (substring(file, 1L, 1L) == "|") {
            file <- pipe(substring(file, 2L), "w")
            on.exit(close(file))
        }
        else {
            file <- file(file, ifelse(append, "a", "w"))
            on.exit(close(file))
        }
    .Internal(cat(list(...), file, sep, fill, labels, append))
}
<bytecode: 0x7fc8a7d676e8>
<environment: namespace:base>
```

When multiple arguments are passed to a function, the majority of languages require them to be comma-separated:

```python
max(1, 5, 42, 19)
```

This pattern -- comma-separated parameters within parentheses to indicate arguments being passed to a function -- [goes back to the very first programming languages](https://en.wikipedia.org/wiki/Plankalk%C3%BCl) and was likely [inspired by mathematical notation](https://en.wikipedia.org/wiki/Function_(mathematics)), which looks essentially identical.

But not all languages use this syntax, particularly for functions which may have only one or two parameters.

## Infix, Prefix, Postfix

Algebraic functions, like `+`, `-`, `*`, and `/` (addition, subtraction, multiplication, and division, respectively) are applied in a significantly different way, but we're so used to it we often don't notice.

These _operators_ (functions with short, usually symbolic names) are _infix_ operators, because they're _fix_-ed with-_in_ the arguments:

```scala
3 + 4
5 - 5
5 * 7
6 / 2
```

But each of these is nothing more than a function which takes two arguments and returns a result:

```scala
     plus(3, 4)
    minus(5, 5)
    times(5, 7)
dividedby(6, 2)
```

Most languages hide this from the user, but Scala (as an example), makes this explicit. Any Scala function -- including the arithmetic operators -- can be applied using a particular notation:

```scala
3.+(4)
5.-(5)
5.*(7)
6./(2)
```

You can see that the "addition" function in Scala is actually called `.+()`, and is called from the `3` object. In Scala, _everything_ -- even a raw number -- is an object, and has class methods which can be called from it. Scala adds some [_syntactic sugar_](https://www.james-willett.com/scala-method-notations) to allow users to drop the preceding `.` and the `()` which surround the argument to the function. The result is the familiar notation we saw previously.

__Prefix__ and __postfix__ operators are another kind of function which is applied in an unusual way, but these functions often only have a single argument:

```java
-3     // "negate" function operating on argument '3'
!true  // "not" function (some languages) operating on argument 'true'
~false // "not" function (other languages) operating on argument 'false'
C++    // "increment" operator operating on argument 'C'
--ii   // "decrement" operator operating on argument 'ii'
A.'    // "transpose" function operating on argument 'A'
```

Each of the above functions operates on a single argument. In some cases, the operator comes immediately before the argument, like `-3`, which is the "negate" function applied to the argument `3` (this function simply multiplies the argument by `-1`). These are _prefix_ operators.

In other cases, the operator comes immediately after the argument, like `C++`, where the variable `C` is incremented using the `++` function. These are _postfix_ operators.

In most languages, a prefix or postfix operator must be _immediately adjacent_ to its argument, with no whitespace or any other characters in between. Because of this limitation, these functions are often symbolic, and don't contain any alphabetic characters.

 > Imagine if the `-` operator were instead called `neg`: `-3` would become `neg3`, and a variable called `ate` would be negated with the syntax `negate` -- not very intuitive. Languages like Python which use operators like this (for instance, the logical `not` instead of `!` or `~`) _do require_ whitespace between the function name and the argument, when parentheses are omitted.

We can see that this notation is not unlike the Scala notation seen above, where a bit of "syntactic sugar" (even if it is not explicitly called that by the language specification) hides the nature of these operators, that they are actually single-argument functions.

### LISP

Some languages -- [notably LISP](https://www.tutorialspoint.com/lisp/lisp_functions.htm) -- have a particular kind of notation, where a function's name is simply followed by its arguments, separated by whitespace:

```lisp
(+ 3 4 5)
```

The above code applies the `+` function to the arguments `3`, `4`, and `5`. Every function in LISP operates this way, which is why LISP is often rife with parentheses:

```lisp
(/ (+ (- b) (sqrt (- (* b b) (* 4 a c)))) (* 2 a))
```

That's the quadratic formula, which might look like this in Python:

```python
(-b + sqrt(b**2 - 4*a*c)) / (2*a)
```

> _Note the "power" infix operator, `**`, in the Python code above._

## Domain-Specific Function Application

Some languages allow particular syntax for particular actions, as well. For instance, many languages support [array indexing with square brackets](https://softwareengineering.stackexchange.com/q/368256/294935):

```c
int arr[] = { 1, 2, 3 };
arr[1]; // == 2
```

...but what is this except a function applied to an array which returns an element of that array? This is a really unusual notation in which one argument (the array name) comes before the "parameter list start" delimiter `[` and the others come before the "parameter list end" delimiter `]`. Similar notation for "slicing" arrays allows extra notation within the square brackets:

```r
arr <- c(1, 2, 3, 4, 5)
arr[2:4]
```

The above R code (which uses 1-based indexing) creates a vector with five elements, then returns the three "middle" elements, `2`, `3`, and `4`, in a new vector.

## Discussion

Function application notation using parentheses and comma-separated argument lists has existed in mathematics for hundreds of years. It is, of course, difficult to judge if this syntax is inherently intuitive or if this notation is simply so ubiquitous now that we don't question it.

We seem able to internalise -- and accept as normal -- other kinds of function application notation, particularly infix, postfix, and prefix notation. Infix notation, in particular, is taught from early grade school, and is therefore easy enough to translate from algebra to programming.

LISP notation seems foreign to beginners, though. But why should it? It's not a big leap from

```c
a + b + c + d
```

to

```python
plus(a, b, c, d)
```

to

```lisp
(+ a b c d)
```

It seems like it's the _nesting_ nature of LISP which makes it difficult. Programs with multiple functions and arguments intertwined can be difficult to parse, as we saw earlier:

```lisp
(/ (+ (- b) (sqrt (- (* b b) (* 4 a c)))) (* 2 a))
```

...but indentation can make this a bit more intelligible:

```lisp
(/
  (+
    (- b)
    (sqrt
      (- (* b b) (* 4 a c)))
  )
  (* 2 a)
)
```

So what's the best way to go about this? Having multiple different ways of applying functions -- with and without syntactic sugar -- feels messy. Is there a way to unify this notation in a way that doesn't feel as clunky as LISP?