65

In many languages, the syntax function_name(arg1, arg2, ...) is used to call a function. When we want to call the function without any arguments, we must do function_name().

I find it odd that a compiler or script interpreter would require () to successfully detect it as a function call. If a variable is known to be callable, why wouldn't function_name; be enough?

On the other hand, in some languages we can do: function_name 'test'; or even function_name 'first' 'second'; to call a function or a command.

I think parentheses would have been better if they were only needed to declare the order of priority, and in other places were optional. For example, doing if expression == true function_name; should be as valid as if (expression == true) function_name();.

The most annoying thing in my opinion is to do 'SOME_STRING'.toLowerCase() when clearly no arguments are needed by the prototype function. Why did the designers decide against the simpler 'SOME_STRING'.lower?

Disclaimer: Don't get me wrong, I love the C-like syntax! ;) I'm just asking if it could be better. Does requiring () have any performance advantages, or does it make understanding the code easier? I'm really curious as to what exactly the reason is.

  • 103
    What would you do if you wanted to pass a function as an argument to another function? – Vincent Savard Oct 5 '16 at 13:50
  • 30
    As long as code is needed to be read by humans, readability is king. – Tulains Córdova Oct 5 '16 at 14:22
  • 75
    That's the thing with readability, you ask about (), yet the thing that stands out in your post is the if (expression == true) statement. You worry about superfluous ()'s, yet then use a superfluous == true :) – David Arno Oct 5 '16 at 14:41
  • 15
    Visual Basic allowed this – edc65 Oct 5 '16 at 14:44
  • 14
    It was mandatory in Pascal, you only used parens for functions and procedures that took arguments. – RemcoGerlich Oct 5 '16 at 14:54

10 Answers 10

251

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.

  • 9
    You might want to mention that this difference is only interesting in the presence of side effects - for a pure function it doesn't matter – Bergi Oct 5 '16 at 15:54
  • 73
    @Bergi: It matters a lot for pure functions! If I have a function make_list that packs its arguments into a list, there's a big difference between f(make_list) passing a function to f or passing an empty list. – user2357112 Oct 5 '16 at 16:03
  • 12
    @Bergi: Even then, I'd still want to be able to pass SATInstance.solve or some other incredibly expensive pure function to another function without immediately attempting to run it. It also makes things really awkward if someFunction does something different depending on whether someFunction is declared to be pure. For example, if I have (pseudocode) func f() {return g}, func g() {doSomethingImpure}, and func apply(x) {x()}, then apply(f) calls f. If I then declare that f is pure, then suddenly apply(f) passes g to apply, and apply calls g and does something impure. – user2357112 Oct 5 '16 at 16:42
  • 6
    @user2357112 The evaluation strategy is independent from purity. Using the syntax of calls as an annotation when to evaluate what is possible (but probably awkward), however it doesn't change the result or its correctness. Regarding your example apply(f), if g is impure (and apply as well?) then the whole thing is impure and breaks down of course. – Bergi Oct 5 '16 at 16:52
  • 14
    Examples of this are Python and ECMAScript, both of which don't really have a core concept of "methods", instead you have a named property that returns an anonymous first-class function object and then you call that anonymous first-class function. Specifically, in both Python and ECMAScript, saying foo.bar() is not one operation "call method bar of object foo" but rather two operations, "dereference field bar of object foo and then call the object returned from that field". So, the . is the field selector operator and () is the call operator and they are independent. – Jörg W Mittag Oct 5 '16 at 18:52
63

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?

  • Thanks, and you gave valid reasons as to why this is important. Can you also give some examples as to why language designers should use functions in prototypes, please? – David Refoua Oct 5 '16 at 14:07
  • the presence of parentheses leaves no doubt that it is a method call I agree completely. I prefer my programming languages to more explicit than implicit. – Corey Ogburn Oct 5 '16 at 15:02
  • 20
    Scala is actually a bit more subtle than that: while other languages only allow one parameter list with zero or more parameters, Scala allows zero or more parameter lists with zero or more parameters. So, def foo() is a method with one empty parameter list, and def foo is a method with no parameter list and the two are different things! In general, a method with no parameter list needs to be called with no argument list and a method with an empty parameter list needs to be called with an empty argument list. Calling a method with no parameter list with an empty argument is actually … – Jörg W Mittag Oct 5 '16 at 18:04
  • 19
    … interpreted as calling the apply method of the object returned by the method call with an empty argument list, whereas calling a method with an empty parameter list without an argument list may depending on context be variously interpreted as calling the method with an empty argument list, η-expansion into a partially applied method (i.e. "method reference"), or it might not compile at all. Also, Scala follows the Uniform Access Principle, by not (syntactically) distinguishing between calling a method without an argument list and referencing a field. – Jörg W Mittag Oct 5 '16 at 18:07
  • 3
    Even as I come to appreciate Ruby for the absence of required "ceremony" - parens, braces, explicit type - I can tell that method-parenthesis reads faster; but once familiar idiomatic Ruby is quite readable and definitely faster to write. – radarbob Oct 6 '16 at 13:21
19

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!

  • 3
    And that is why empty parentheses () resemble spoons minus the handle. – Mindwin Oct 5 '16 at 18:45
  • 3
    Defining a leq function that uses < rather than <= is quite confusing! – KRyan Oct 5 '16 at 19:57
  • 5
    This answer might be easier to understand if it used the word "tuple" in addition to phrases like "product type." – Kevin Oct 6 '16 at 1:43
  • Most formalisms will treat int f(int x,int y) as a function from I^2 to I. Lambda calculus is different, it does not use this method to match what in other formalisms is high arity. Instead lambda calculus uses currying. Comparison would be x->(y->(x<=y)). (x->(y->(x<=y)) 2 would evaluate to (y->2<=y) and (x->(y->(x<=y)) 2 3 would evaluate to (y->2<=y) 3 which in turn evaluates to 2<=3. – Taemyr Oct 6 '16 at 7:49
  • 1
    @PeriataBreatta I am not familiar with the history of using () to represent the unit. I would not be surprised if at least part of the reason was to resemble a "parameterless function". However, there is another possible explanation for the syntax. In the algebra of types, Unit is in fact the identity for product types. A binary product is written as (a,b), we could write a unary product as (a), so a logical extension would be to write the nullary product as simply (). – gardenhead Oct 7 '16 at 14:13
14

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.

  • 4
    +1 As long as code is needed to be read by humans, readability is king. – Tulains Córdova Oct 5 '16 at 14:22
  • 1
    @TulainsCórdova I'm not sure perl agrees with you. – Racheet Oct 5 '16 at 16:36
  • @Racheet: Perl may not but Perl Best Practices does – slebetman Oct 6 '16 at 4:15
  • 1
    @Racheet Perl is very readable if it's written to be readable. That's the same for pretty much every non-esoteric language. Short, concise Perl is very readable to Perl programmers, just like Scala or Haskell code is readable to people experienced in those languages. I can also speak German to you in a very convoluted manner that is grammatically completely correct, but still you won't understand a word, even if you're proficient in German. That's not German's fault either. ;) – simbabque Oct 6 '16 at 10:39
  • in java it does not "identify" a method. It calls it. Object::toString identifies a method. – njzk2 Oct 6 '16 at 21:23
10

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.

  • 2
    Well, "easily" is one of those "it's clear only if its already understood" situations. A beginner would be entirely justified in noting that it is by no means obvious without explanation why some punctuation has the meaning it has. – Eric Lippert Oct 5 '16 at 17:08
  • 2
    @EricLippert: Indeed, easily does not necessarily mean intuitive. Though in this case I would point that parentheses are also used for function "invocation" in mathematics. That being said, I've found beginners in many languages struggling more with concepts/semantics than syntax in general. – Matthieu M. Oct 5 '16 at 17:20
  • This answer confuses the distinction between "currying" and "partial application". The :: operator in Java is a partial application operator, not a currying operator. Partial application is an operation that takes a function and one or more values and returns a function accepting fewer values. Currying operates only on functions, not values. – Periata Breatta Oct 7 '16 at 8:55
  • @PeriataBreatta: Good point, fixed. – Matthieu M. Oct 7 '16 at 9:32
8

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.

  • 1
    Note that the OP presented the case where an object is the only argument and is presented before the function name (which also provides a scope for the function name). noun.verb syntax could be as clear in meaning as noun.verb() and slightly less cluttered. Similarly, a function member_ returning a left reference might offer a friendly syntax than a typical setter function: obj.member_ = new_value vs. obj.set_member(new_value) (the _ postfix is a hint saying "exposed" reminiscent of _ prefixes for "hidden" functions). – Paul A. Clayton Oct 6 '16 at 1:02
  • 1
    @PaulA.Clayton I don't see how this isn't covered by my answer: If noun.verb means function invocation, how do you differentiate it from mere member access? – Daniel Jour Oct 6 '16 at 7:52
  • 1
    In regards to reading variables being theoretically free of side effects, I just want to say this: Always beware of false friends. – Justin Time Oct 6 '16 at 23:16
7

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.

  • In a sense I agree: programming languages should have a “safety net” mechanism. But I disagree that “a little redundancy” in the syntax is a good way to go about it – that's boilerplate, and what it mostly does is introduce noise which makes errors harder to spot, and opens up possibilities for syntax errors which distract from the real bugs. The kind of verbosity that aids readability has little to do with syntax, more with naming conventions. And a safety net is by far most efficiently implemented as a strong type system, in which most random changes will make the program ill-typed. – leftaroundabout Oct 9 '16 at 22:55
  • @leftaroundabout: I like to think about language design decisions in terms of Hamming distance. If two constructs have different meanings, it's often helpful to have them differ in at least two ways, and have a form which differs in only one way generate a compiler squawk. The language designer generally can't be responsible for ensuring that identifiers are easily distinguishable, but if e.g. assignment requires := and comparison ==, with = only being usable for compile-time initialization, then the likelihood of typos turning comparisons into assignments would be greatly diminished. – supercat Oct 10 '16 at 15:50
  • @leftaroundabout: LIkewise, if I were designing a language, I would likely require () for invocation of a zero-argument function but also require a token to "take the address of" a function. The former action is much more common, so saving a token in the less common case isn't all that useful. – supercat Oct 10 '16 at 15:53
  • @supercat: well, again I think this is solving the problem on the wrong level. Assignment and comparison are conceptually different operations, so are function evaluation and function-adress taking, respectively. Hence they should have clearly distinct types, then it doesn't really matter anymore if the operators have a low Hamming distance, because any typo will be a compile-time type error. – leftaroundabout Oct 10 '16 at 16:03
  • @leftaroundabout: If an assignment is being made to a boolean-type variable, or if a function's return type is itself a pointer to a function (or--in some languages--an actual function), replacing a comparison with an assignment, or a function invocation with a function reference, may yield a program which is syntactically valid, but has totally different meaning from the original version. Type checking will find some such errors in general, but making the syntax distinct seems like a better approach. – supercat Oct 10 '16 at 16:25
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).

  • 2
    Of course, while visual basic's lack of brackets on procedure calls is an unnecessary distinction in comparison with its function calls, adding required brackets to them would be an unnecessary distinction between statements, many of which in a BASIC-derived language have effects that are very reminiscent of procedures. It's also been a while since I did any work in an MS BASIC version, but does it not still allow the syntax call <procedure name> (<arguments>)? Pretty sure that was a valid way of using procedures back when I did QuickBASIC programming in another lifetime... – Periata Breatta Oct 7 '16 at 9:01
  • 1
    @PeriataBreatta: VB still does allow the "call" syntax, and sometimes requires it in cases where the thing to be called is an expression [e.g. one can say "Call If(someCondition, Delegate1, Delegate2)(Arguments)", but direct invocation of the result of an "If" operator would not be valid as a standalone statement]. – supercat Oct 10 '16 at 16:28
  • @PeriataBreatta I liked VB6's no bracket procedure calls because it made DSL-like code look good. – Mark Hurd Oct 14 '16 at 7:19
  • @supercat In LinqPad, it is amazing how often I need to use Call for a method where I almost never need to in "normal" production code. – Mark Hurd Oct 14 '16 at 7:19
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.

  • 3
    JavaScript does not lack a type system. It lacks type declarations. But it's entirely aware of the difference between different types of value. – Periata Breatta Oct 7 '16 at 9:03
  • 1
    Periata Breatta: the point is that Java variables and properties may contain types of any value, so you can't always know whether or not it is a function at code reading time. – reinierpost Oct 7 '16 at 10:17
  • For example, what does this function do? function cross(a, b) { return a + b; } – Mark K Cowan Oct 7 '16 at 10:24
  • @MarkKCowan It follows this: ecma-international.org/ecma-262/6.0/… – curiousdannii Oct 8 '16 at 13:30
4

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.

  • Yup. Consistency is a good enough reason, full stop (not that your other points aren't valid -- they are). – Matthew Read Oct 9 '16 at 21:17

protected by gnat Oct 6 '16 at 14:10

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.