69

The syntax function_name(arg1, arg2, ...) is used widely across various programming languages to invoke a function. Why is it necessary for the compiler or interpreter to require () to recognize it as a function call? If something is inherently callable, wouldn't function_name; suffice to execute it?

In certain languages, you can execute a function or command using syntax such as function_name 'test'; or even function_name 'first' 'second';. Bash is one example. Some constructs (e.g., 'echo' or 'include') operate this way as well, like in PHP.

Could parentheses have been reserved solely for establishing the order of precedence, making them optional elsewhere? For instance, if expression == true function_name; would've been as valid as if (expression == true) function_name();.

A particularly interesting case is the use of 'SOME_STRING'.toLowerCase() in JavaScript, where no arguments are required by the prototype method. Why did language designers opt against the simpler 'SOME_STRING'.lower design in this case?

Disclaimer: I genuinely appreciate the syntax design of the C-inspired languages! I'm merely curious about the rationale behind this design choice. Does requiring () provide any genuine benefits, or does it simply enhance code readability for humans?

David Refoua
  • 1,219

11 Answers11

256

For languages that use first-class functions, its quite common that the syntax of referring to a function is:

a = object.functionName

while the act of calling that function is:

b = object.functionName()

a in the above example would be reference to the above function (and you could call it by doing a()), while b would contain the return value of the function.

While some languages can do function calls without parenthesis, it can get confusing whether they are calling the function, or simply referring to the function.

66

Indeed, Scala allows this, though there is a convention that is followed: if the method has side-effects, parentheses should be used anyway.

As a compiler writer, I would find the guaranteed presence of parentheses quite convenient; I would always know that is a method call, and I wouldn't have to build in a bifurcation for the odd case.

As a programmer and code reader, the presence of parentheses leaves no doubt that it is a method call, even though no parameters are passed.

The passing of parameters is not the sole defining characteristic of a method call. Why would I treat a parameter-less method any different from a method that has parameters?

Robert Harvey
  • 200,592
22

This is actually a pretty subtle fluke of syntax choices. I'll speak to functional languages, which are based on the typed lambda calculus.

In said languages, every function has exactly one argument. What we often think of as "multiple arguments" is actually a single parameter of product type. So for example, the function that compares two integers:

leq : int * int -> bool
leq (a, b) = a <= b

takes a single pair of integers. The parentheses do not denote the function parameters; they are used to pattern-match the argument. To convince you that this is really one argument, we can instead use the projective functions instead of pattern matching to deconstruct the pair:

leq some_pair = some_pair.1 <= some_pair.2

Thus, the parentheses really are a convenience that allows us to pattern match and save some typing. They are not required.

What about a function that ostensibly has no arguments? Such a function actually has domain Unit. The single member of Unit is usually written as (), so that's why the parentheses appear.

say_hi : Unit -> string
say_hi a = "Hi buddy!"

To call this function, we would have to apply it to a value of type Unit, which must be (), so we end up writing say_hi ().

So, there is really no such thing as an arguments list!

gardenhead
  • 4,757
15

In Javascript for instance using a method name without () returns the function itself without executing it. This way you can for instance pass the function as an argument to another method.

In Java the choice was made that an identifier followed by () or (...) means a method call while an identifier without () refers to a member variable. This might improve readability, as you have no doubt whether you are dealing with a method or a member variable. In fact, the same name can be used both for a method and a member variable, both will be accessible with their respective syntax.

Florian F
  • 1,136
  • 1
  • 6
  • 13
11

Syntax follows semantics, so let's start from semantics:

What are the ways of using a function or method?

There are, actually, multiple ways:

  • a function can be called, with or without arguments
  • a function can be treated as a value
  • a function can be partially applied (creating a closure taking at least one less argument and closing over the passed arguments)

Having a similar syntax for different uses is the best way to create either an ambiguous language or at the very least a confusing one (and we have enough of those).

In C, and C-like languages:

  • calling a function is done by using parentheses to enclose the arguments (there might be none) as in func()
  • treating a function as a value can be done by simply using its name as in &func (C creating a function pointer)
  • in some languages, you have short-hand syntaxes for partially applying; Java allows someVariable::someMethod for example (limited to the method receiver, but still useful)

Note how each usage features a different syntax, allowing you to tell them apart easily.

Matthieu M.
  • 15,214
11

None of the other answers have attempted to tackle the question: how much redundancy should there be in the design of a language? Because even if you can design a language so that x = sqrt y sets x to the square root of y, that doesn't mean you necessarily should.

In a language with no redundancy, every sequence of characters means something, which means that if you make a single mistake, you won't get an error message, your program will do the wrong thing, which might be something very different from what you intended and very difficult to debug. (As anyone who has worked with regular expressions will know.) A little redundancy is a good thing because it enables many of your errors to be detected, and the more redundancy there is, the more likely it is that the diagnostics will be accurate. Now of course, you can take that too far (none of us want to write in COBOL these days), but there is a balance that is right.

Redundancy also helps readability, because there are more clues. English without redundancy would be very hard to read, and the same is true of programming languages.

Michael Kay
  • 3,599
  • 1
  • 17
  • 13
7

In a language with side effects it's IMO really helpful to differentiate between (in theory side effect free) reading of a variable

variable

and calling a function, which might incur side effects

launch_nukes()

OTOH, if there are no side effects (other than those encoded in the type system) then there's no point to even differentiate between reading a variable and calling a function with no arguments.

6

Consistency and readability.

If I learn that you call the function X like this: X(arg1, arg2, ...), then I expect it to work the same way for no arguments: X().

Now at the same time I learn that you can define the variable as some symbol, and use it like this:

a = 5
b = a
...

Now what would I think when I find this?

c = X

Your guess is as good as mine. In normal circumstances, the X is a variable. But if we were to take your path, it could also be a function! Am I to remember whether which symbol maps to which group(variables/functions)?

We could impose artificial constraints, e.g. "Functions start with capital letter. Variables start with lower-case letter", but that's unneccessary and makes things more complicated, although might sometimes help some of the design goals.

Side-note 1: Other answers completely ignore one more thing: language might allow you to use the same name for both function and variable, and distinguish by context. See Common Lisp as an example. Function x and variable x coexist perfectly fine.

Side-note 2: The accepted answer shows us the syntax: object.functionname. Firstly, it's not universal to languages with first-class functions. Secondly, as a programmer I would treat this as an additional information: functionname belongs to an object. Whether object is an object, a class or a namespace doesn't matter that much, but it tells me that it belongs somewhere. This means you have to either add artificial syntax object. for each global function or create some object to hold all global functions.

And either way, you lose the ability to have separate namespaces for functions and variables.

MatthewRock
  • 819
  • 1
  • 6
  • 15
5

In most cases, these are syntactic choices of the grammar of the language. It is useful for grammar for the various individual construct to be (relatively) unambiguous when taken all together. (If there are ambiguities, like in some C++ declarations, there have to be specific rules for resolution.) The compiler doesn't have the latitude for guessing; it is required to follow the language specification.


Visual Basic, in various forms, differentiates between procedures that don't return a value, and functions.

Procedures must be called as a statement, and don't require parens, just comma separated arguments, if any. Functions must be called as part of an expression, and require the parens.

It is a relatively unnecessary distinction that makes manual refactoring between the two forms more painful than it has to be.

(On the other hand Visual Basic uses the same parens () for array references as for function calls, so array references look like function calls. And this eases manual refactoring of an array into a function call! So, we could ponder other languages use []'s for array references, but I digress...)


In the C and C++ languages the contents of variables are automatically accessed by using their name, and if you want to refer to the variable itself instead of its contents, you apply the unary & operator.

This kind of mechanism could also be applied to function names. The raw function name could imply a function call, whereas a unary & operator would be used to refer to the function (itself) as data. Personally, I like the idea accessing side-effect-free no-argument functions with the same syntax as variables.

This is perfectly plausible (as are other syntactic choices for this).

Erik Eidt
  • 34,819
4

To add to the other answers, take this C example:

void *func_factory(void)
{
        return 0;
}

void *(*ff)(void);

void example()
{
        ff = func_factory;
        ff = func_factory();
}

If the invocation operator was optional, there would be no way to distinguish between the function assignment and the function call.

This is even more problematic in languages lacking a type system, e.g. JavaScript, where type inference cannot be used to figure out what is and isn't a function.

0

The real reason why you need parentheses for function calls with no arguments is that Mr. Ritchie thought it was better that way and implemented it that way. And that afterwards, nobody could come up with a reason to not require parentheses that was good enough to justify a language change.

And Pascal doesnt require parentheses because Mr. Wirth made the opposite decision. Unfortunately it is too late now to ask either if in hindsight they would have decided otherwise.

But that is the common answer to many why questions: Because someone thought they had a good idea.

gnasher729
  • 49,096