4
$\begingroup$

I understand that in programming languages in general, function routines have what I can generally name a parameter set (or "list"), usually symbolized with parenthesis and if it is not empty, it is also utilized in function calls.

In JavaScript:

function myFunction (passed_parameter_1, passed_parameter_2) {
    // Some code...
}

myFunction(corresponding_passed_argument_1, corresponding_passed_argument_2);

My problem

I never learned in programming courses:

  • What is the name of that feature
  • why, in programming languages in general, a user must have this feature, even if the parameter set in routine and the corresponding argument set in call, are both empty.
  • Why not let a user define a group of parameters (or not) per need, only inside a routine's scope instead

Interim note

  • One could claim it is needed for a compiler to know what is a function but a keyword such as function reinforce the opinion that it isn't.

  • One can claim it is needed for separation of internal implementation and external interface but such separation could be done as two different sub-scopes of the main scope ({}), for example:

function myFunction {
    par myPar1
    par myPar2

    // some code

}

myFunction {1,2}

My question

Why, in programming languages in general, must function declarations be followed by a parameter set, external to the sub-routine scope?

$\endgroup$
2
  • $\begingroup$ Comments are not for extended discussion; this conversation has been moved to chat. $\endgroup$
    – D.W.
    Commented Feb 18, 2020 at 16:39
  • $\begingroup$ The arguments are variables local to the function, but special in that they are interface to the world. Thus often considered separately. $\endgroup$
    – vonbrand
    Commented Feb 23, 2020 at 16:27

9 Answers 9

19
$\begingroup$

In my opinion, your question is formed on the basis of working with a small number of programming languages and extrapolating conclusions that may not be valid.

Here are some assumptions I have recognised that may not be valid which I will later explore in greater detail:

  • All function calls must use parenthesis.
  • All programming languages use these syntactic notations to mean the same thing
  • There is some common underlying nature that requires things to be like this

I further understand you hinted that you have no significant background in Computer Science theory, but some of the background material to why functions are usually written like this, is about the theoretical evolutionary route that most current languages came from;
So, lets review some of that, as it may help readers (such as students of Computer Science and programming per se) understand your question and our answers more fully.

Consider an early computer language, such as Fortran, which was devised in 1954. It had functions and used parentheses. Actually, at that time the character set available on computer was so limited that it had no other bracketing symbols, and only had upper case letters. It did not have access to []{}<> symbols. Originally all comparisons were made to zero so that comparison operators were not needed, but when they were later introduced they had to be written as .GT. and .LT. due to the lack of characters. The result of this was we could write:

       FUNCTION B
       B=1.0
       RETURN

       FUNCTION C(D)
       C = D
       RETURN

       DIMENSION A(10)
       A(1) = C(1) + B
       STOP
       END

You can see that we have used parentheses for A(1) (which is an array) and C(1) which is a function call, but not for + B which is also a function call. We have used parentheses for A(10) which is an array declaration and also for C(D) which is a function declaration with a formal parameter. Thee design on the language is such that the compiler can work out what is intended and instruct the computer in its machine code to take appropriate actions. However, sometimes this is not convenient for the compiler writer as that may require multiple passes (or readings) of the program to determine what use of parenthesis was intended before determining the semantics of that fragment of code.

Algol 60 also has a similar situation, shown in this example:

integer function one;
begin
one := 1
end;

integer function two (integer p);
begin
two := p
end;

begin
integer array a [ 1: 10 ];
a[one] := two(1)
end

In the above example one is a function that uses no parentheses in its declaration or invocation, whereas two is a function that used parentheses to indicate the formal parameter list (integer p) and also the actual argument (1). this time they are not confused with arrays at all, because the array exclusively used [] in both its declaration and application. So thus invalidating your assumption on what () might mean.

We also get some symbol overloading in more modern advanced languages. Take Algol 68 for example. It also uses parentheses for arrays and functions (but also almost everything else), but also like Algol 60 that proceeded it, it uses square brackets []:

( [] int a := (1,2,3);
print((a[1])) )

Here '[]' are used to indicate the array declaration, whereas (1,2,3) indicates the array constant used to initialise it. The print statement is even more complex. The inner parentheses (a[1]) indicate an array constant containing one element and the outer print() indicates a function call, and the [1] indicates an array selection operation. The all-encompassing () are used for the program begin and end.

One more historical language is important here, which is LISP. Using LISP we can explore functions as first class objects, lambda functions and other aspects of functions and the notation associated with them. In LISP we can store a function in a named variable like this:

(setq double (function (lambda (x) (+ x x)) ))

Notice that everything is using parentheses; that is the nature of LISP. LISP is constructed entirely of lists denoted by the tuples in parentheses like this:

(x x x x)

Those lists can be either or both data and functions, it makes no difference. Now that the name double contains a function we can do various things with it.

We can invoke the function like this:

(funcall double 11)

This leads into coverage of the notation used in command command languages such as Windows/DOS command prompt and unix shells. In them each line is essentially a function call:

cd path/file

Function calls can be nested by using backtick notation:

cd `which file`

Here no parentheses have been used at all, yet it is a notation familiar to many experienced computer users.

I have not really covered other uses of functions and their notations, such as functions as first class objects, passing functions as arguments, partial parameterisation, lazy evaluation and many many more concepts that could shine a light onto why function notation is as it is. We have to have a notation to ultimately say: This name is a function and I want it to be invoked at this point.

Some of what we are exploring here is the separation between programming language syntax and its semantics. How much of the symbols indicate structure and how much communicate meaning (semantics), and how can this be determined by automated means. An introduction (to a deeper) theoretical topic can be started by looking at Chomsky Language Hierarchy. Algol 60's nice separation of [] from () meant that a Context Free Grammar could be used to describe the syntax of the language. Algol 68, in contrast, by the use of symbol overloading (and for other reasons) mean that a more complex Context Sensitive Grammar (known as W-grammars) needed to be used.

The more complex the grammar needed to express the language the more complex the compiler implementation. Language designers wanted both a powerful and expressive language, but also one that could be implemented without undue complexity in the compiler. This often resulted in some stereotyping of language features in ways that were know to be implemented more easily.

In the evolution of languages they developed into different families as they grew from one to another. To prevent the overloading of () meaning begin and end the use of the symbols {} became common place, and the use of [] for array was considered sensible. However many languages use () to indicate both formal parameters and actual arguments, but this is by no means a universal characteristic, and there are exceptions to everything.

When we think that many languages seem to use the name() notation for function invocation, what we are really seeing is that many languages in common use today inherit a set of notations from the C family of languages through the Algol route. That is all we are seeing is the genealogy of language in the notations.

I hope by a brief tour on the history of the use of parenthesis in the evolution of computer languages and its relation to computer science theory you have gained an insight into what you are trying to understand.


And if it matters: yes I have worked on Fortran, Algol 60, Algol 68 and other esoteric language compilers

$\endgroup$
7
  • 4
    $\begingroup$ Just add that the usage of f(x) is in large part to cater to familiarity with mathematical notation $f(x)$. There are laguages that use parentesis almost only for expression grouping (like APL), and even only for structuring (like Scheme). Most popular current languages loosely inherit from Algol 60, very often by the way of C. So they have an erie similarity, and a casual obsever can think there is something fundamental, not just common convention and borrowing from other areas, behind it all. $\endgroup$
    – vonbrand
    Commented Feb 18, 2020 at 4:43
  • $\begingroup$ Take a look at FORTH for a radically different way of taking the idea of "calling a function"... $\endgroup$
    – vonbrand
    Commented Feb 18, 2020 at 22:46
  • $\begingroup$ Hello to all answerers: I now give 100rep bounty to improve details as this question was fully changed after it was merged with my new, better question which includes more accurate terminology, is more exampled and more carefully worded. I invite to consider edit your answers per the updates in question; I know this might seem sisyphic, but I think it would be helpful for future readers and will help you help me also. I have explained in the bounty message the whole mess behind this merging. So, for you consideration. No irreverence intended. $\endgroup$
    – user115711
    Commented Feb 19, 2020 at 1:52
  • $\begingroup$ I am going to leave this website soon; I have joined here essentially to ask this question; I hope you will agree to update the answer per the updated question; if the answer is updated, I could accept the answer, give you the bounty and upvote, but if it isn't done an answer to the old question is kept, I must leave without this; please tell me if you mean to update the answer per the updated question so I would know if I can delete my profile today or afterwards. $\endgroup$
    – user115711
    Commented Feb 20, 2020 at 18:57
  • 1
    $\begingroup$ It seems to me that you're expecting a definitive answer to the question of "why is the conventional notation the conventional notation?" - the answer is that it's just convention, used in most but not all mainstream cases precisely because it is conventonal. $\endgroup$
    – user115736
    Commented Feb 21, 2020 at 19:29
12
$\begingroup$

This notation is seen as useful to differentiate variables from function calls (both for humans and compiler parsers):

a = 12;
int b = a;

versus

int a() { return 12; }
int b = a();

Furthermore, when a is a function, a without parentheses can represent the function pointer itself (in Python for instance, or in C if preceded by &)

Note that it is not universally true: some languages like Ada don't require (and will reject) parentheses when the function takes no arguments, making it undifferentiable from a variable out of context. And function pointers use a different notation.

$\endgroup$
4
  • 3
    $\begingroup$ It mightbe worth to add that this is about compiler/interpreter design. With parentheses the compiler knows right away (i.e. without any lookup or second pass) that a reference is meant to be a function call and can generate code accordingly. They work as a typing identifier - much like a !$% in BASIC. $\endgroup$
    – Raffzahn
    Commented Feb 16, 2020 at 8:59
  • 2
    $\begingroup$ @Raffzahn: Not just the compiler, it's also very useful for the human trying to read that code :-) $\endgroup$
    – jamesqf
    Commented Feb 16, 2020 at 17:50
  • 1
    $\begingroup$ In C/C++ & before taking a function pointer is essentially optional. $\endgroup$ Commented Feb 16, 2020 at 18:18
  • $\begingroup$ Hello to all answerers: I now give 100rep bounty to improve details as this question was fully changed after it was merged with my new, better question which includes more accurate terminology, is more exampled and more carefully worded. I invite to consider edit your answers per the updates in question; I know this might seem sisyphic, but I think it would be helpful for future readers and will help you help me also. I have explained in the bounty message the whole mess behind this merging. So, for you consideration. No irreverence intended. $\endgroup$
    – user115711
    Commented Feb 19, 2020 at 1:52
9
$\begingroup$

The problem a compiler must solve is the use-mention distinction. Are we using the subroutine or function (i.e., calling it), or just mentioning it (i.e., just needing its identification -- I refrain from talking about 'pointers' since the same problem exists in languages without the concept of pointers).

Even if you have a language that demands declaration before use, and/or has a multipass compiler, so that you know FOO is the name of a subroutine rather than the name of a variable, there is still the problem of knowing what you're supposed to do when the name FOO is encountered without parentheses.

In the simplest case: is X := FOO; a call of FOO or not? The answer generally depends on the effective type of X, though note that X itself may have the same problem of resolution. There are at least the following possibilities:

  • X is an integer variable, FOO is a function returning an integer value -> it's a call to FOO.

  • X is a reference to a function returning an integer value, FOO is a function returning an integer value -> it's not a call to FOO, the result is that X now refers to the function named FOO.

  • X is a function returning a reference to an integer variable, and FOO is a function returning an integer value -> both X and FOO are called.

  • X is a function returning a reference to a function returning an integer, FOO is a function returning an integer -> X is called, FOO is not called; whatever reference X returned now refers to the function FOO.

Many early languages did not require parentheses on a call to a subroutine or function that required no arguments. They handled use/mention distinction by other means. The simpler the language, the simpler those 'other means' could be -- might be as simple as an explicit CALL statement for a subroutine.

A particularly interesting example was the language Algol 68, which had fairly involved rules about when a 'procedure value' could be 'deprocedured' (i.e., called to yield a value). The deproceduring coercion applies only to procedures without parameters.

The modern taste, however, is to avoid that particular complexity by making it explicit when a call is required - by having parentheses to indicate a call even though the parameter-list is empty. You might consider the change to be from implicit semantics to explicit semantics; Algol 68's system of implicit type conversions ('coercions' in the jargon) were sometimes thought to be overly complex.


With respect to this part: I am just baffled to understand what you mean:

I don't understand what is the name of this feature and why not let a user define arrays (or not) per need, only inside a routine's scope instead.

The name of the feature would be 'function or subroutine arguments' if anyone bothered to name it.

Suppose we write a function to compute square roots: we define it by something like (pseudocode follows): function sqrt(real arg) : real { ... }, to be read 'the function sqrt takes a real argument, represented by the formal name arg, and returns a real value'.

Now to call that, we write something like y := sqrt(42.0). The caller is telling the function what value to use for its argument arg. That should be clear, right? Neither 'arg' not '42.0' constitutes an array; they are the formal arguments and actual arguments, respectively, of the sqrt function. And they're certainly not 'defaults'.

How could 'arg' be defined 'in a routine's scope' in any more concise manner? 3 facts about it are needed: its formal name, its data type, and the important one, that it is the name of a formal argument for which the caller must supply an actual argument.

A similar function with no formal argument could be declared without parentheses in the syntax I chose: function FOO : real { ... } but that's a consequence of the syntax I made up. However, we'd still be left with the need to determine the meaning of the appearance of the name FOO elsewhere: is X := FOO a call or not?

$\endgroup$
2
  • $\begingroup$ Hello to all answerers: I now give 100rep bounty to improve details as this question was fully changed after it was merged with my new, better question which includes more accurate terminology, is more exampled and more carefully worded. I invite to consider edit your answers per the updates in question; I know this might seem sisyphic, but I think it would be helpful for future readers and will help you help me also. I have explained in the bounty message the whole mess behind this merging. So, for you consideration. No irreverence intended. $\endgroup$
    – user115711
    Commented Feb 19, 2020 at 1:52
  • $\begingroup$ This answer is mostly about the need for parentheses on a function invocation; the question it is now attached to is now only concerned with function declarations. Alas, I cannot modify it since I answered as a guest (I followed the question here from retrocomputing and didn't think I'd be sticking around). $\endgroup$
    – user115736
    Commented Feb 19, 2020 at 12:50
4
$\begingroup$

There are at least 3 things a function declaration needs to tell the compiler.

  • It's a function declaration.

  • The name (if any) of the function being declared.

  • The names of the arguments (if any).

You can devise any syntax you like that will convey those things. However, there's a certain preference for syntax that either resembles mathematical use, or resembles previous programming language use. These days, in 'mainstream' languages, that usually leads to parentheses, because in such cases there's no particular benefit in doing otherwise.

To make a case for not using parentheses, I think you'd have to argue that your alternative is consistent with the rest of the language syntax, and/or there are advantages of expression that you get by not following the de facto standard.

In your specific example (function … par) you have added two new keywords to the language, which is probably two reserved words: proliferation of reserved words is generally avoided if it can be. Further, IMO it's made the language harder to read since now the related concepts of 'declaration' and 'call' now have entirely different syntax. Those two costs appears to have no corresponding benefits.

To sum up: there is no 'must' about it; a language definer is free to define his language however he chooses. However, there are forces which operate: overall linguistic consistency, and the desire to not make familiar mechanisms look arbitrarily different.

$\endgroup$
3
  • $\begingroup$ In e.g. the Unix shells, the parameters are just separated by spaces. No parentheses at all. $\endgroup$
    – vonbrand
    Commented Feb 18, 2020 at 4:46
  • $\begingroup$ Hello to all answerers: I now give 100rep bounty to improve details as this question was fully changed after it was merged with my new, better question which includes more accurate terminology, is more exampled and more carefully worded. I invite to consider edit your answers per the updates in question; I know this might seem sisyphic, but I think it would be helpful for future readers and will help you help me also. I have explained in the bounty message the whole mess behind this merging. So, for you consideration. No irreverence intended. $\endgroup$
    – user115711
    Commented Feb 19, 2020 at 1:53
  • $\begingroup$ @vonbrand - well, quite: because the original Unix shells were primarily written for interactive ease, not with the same sort of rigor as (we hope) programming language definition. Also to the OP's point, a (bash) function definition statement does not name the formal parameters at all. What your example shows is that there are alternatives that get used where it seems appropriate; but that does not counter that "in general" function declarations are followed by a parameter-list in parentheses. $\endgroup$
    – user115736
    Commented Feb 21, 2020 at 19:34
4
$\begingroup$

On top of what everyone else has said, there is a very good reason why some programming languages did it this way.

"Tuple" call notation in programming languages goes at least back to Fortran. I couldn't find an earlier example, although MATH-MATIC used parentheses and commas for subscripts. It makes sense, because this is familiar from mathematical notation: $f(x,y)$.

Wirth-family languages adopted the notation. But even more than this, Wirth-family languages have an interesting property which makes them very easy to parse.

(Disclaimer: I believe this is true of ALGOL, but I'm not 100% certain. It's certainly true of Pascal and its derivatives.)

The property is: No two identifiers appear without a keyword or operator between them. A grammar with this property is known as an "operator grammar".

So, for example, in Pascal you would say:

var variable1, variable2: my_type;

Where in C you would say:

my_type variable1, variable2;

In C, the identifiers my_type and variable1 have no keyword or operator between them. Just whitespace. To implement this syntax, C uses "lexical feedback": as soon as a user-defined type has been declared, the lexical analyser must be informed so it can be interpreted as a type name and not a variable name. This is why, in C, a type must be declared before it is used. Without this, C's syntax is not $LR(1)$.

(Technical point: C actually has four distinct identifier namespaces: types, variables, struct members, and goto labels. But this isn't relevant for our discussion.)

So one reason why some languages use tuple notation for calls is to keep the operator grammar property.

There are other alternatives. One, for example, is to keep type names and variable names lexically distinct. Some older languages (e.g. Perl) use sigils. In Haskell, variables begin with lower-case letters and type names begin with upper-case letters.

$\endgroup$
5
  • 2
    $\begingroup$ Algol 60/68 kept keywords, which included type names, lexically distinct by use of underlining (if hardware permitted) or bolding (in the publication language) or some lesser stropping method such as apostrophes. $\endgroup$
    – user115736
    Commented Feb 17, 2020 at 12:16
  • 2
    $\begingroup$ Re: your disclaimer about the Algols. Spaces were ignored, which meant that my variable name was a single identifier, and thus an operator/keyword must appear between two identifiers. There was a pesky exception for bolded words: ref real is ref followed by real and not refreal. I don't know how that was handled in compilers. $\endgroup$
    – user115736
    Commented Feb 17, 2020 at 12:20
  • 1
    $\begingroup$ That's very interesting! ALGOL, of course, was famously the first programming language to be specified using what we now call BNF, and ALGOL 68 was famously one of the first (possibly the first) that couldn't be specified using BNF. I was wondering how ALGOL handled user-defined types. The answer, of course, is that it didn't have them until ALGOL W / ALGOL 68. $\endgroup$
    – Pseudonym
    Commented Feb 17, 2020 at 23:29
  • 2
    $\begingroup$ I'm not so sure that Algol 68 syntax couldn't be specified in BNF if you were willing to have the approximate same level of description as Algol 60 had. However, there was a desire to have the grammar define the semantics as well -- so, for a simple example, the productions (or whatever they're called in the Report) say that you can't use a variable you have never defined, or that modes (types) in expressions need to be compatible - considerations which previously were spelled out in English. $\endgroup$
    – user115736
    Commented Feb 17, 2020 at 23:37
  • $\begingroup$ Hello to all answerers: I now give 100rept bounty to improve details as this question was fully changed after it was merged with my new, better question which includes more accurate terminology, is more exampled and more carefully worded. I invite to consider edit your answers per the updates in question; I know this might seem sisyphic, but I think it would be helpful for future readers and will help you help me also. I have explained in the bounty message the whole mess behind this merging. So, for you consideration. No irreverence intended. $\endgroup$
    – user115711
    Commented Feb 19, 2020 at 1:53
3
$\begingroup$

An exception was Pascal, where using the name of a function with no arguments called it, and assigning to the name of a function assigned to it. It was considered a good idea back then. I always thought it made code less readable.

Today, look at a language like Swift where a function is a first class object. Which can be stored into a variable, passed as a parameter etc. The function name on its own is a function, not a function call. And () is the function call operator.

Must function names be followed by empty parentheses if there are no argument? Of course not, there is no must. But over the last fifty years, more and more programming languages have found that using parentheses consistently makes life easier.

$\endgroup$
2
  • $\begingroup$ Hello to all answerers: I now give 100rep bounty to improve details as this question was fully changed after it was merged with my new, better question which includes more accurate terminology, is more exampled and more carefully worded. I invite to consider edit your answers per the updates in question; I know this might seem sisyphic, but I think it would be helpful for future readers and will help you help me also. I have explained in the bounty message the whole mess behind this merging. So, for you consideration. No irreverence intended. $\endgroup$
    – user115711
    Commented Feb 19, 2020 at 1:53
  • $\begingroup$ Also, see Euler, another Wirthy language, a predecessor to Pascal. A procedure denotation looked like 'formal x; formal y; x + y' (where the apostrophes are part of the syntax), and a name is bound to the procedure by assignment - i.e., procedures look to me like first-class objects. The syntactic approach (no parentheses) never caught on in mainstream languages, which further bolsters my position that this is simply a matter of notational convention. $\endgroup$
    – user115736
    Commented Feb 23, 2020 at 20:46
2
$\begingroup$

Well, in the case of Algol family, the answer is yes, most of them has similar syntax. and IMO, Algol family could be treated as representative of general programming languages since there are many of well-known field-tested languages like JS, Pascal, Ruby, Java and C-family language.

FYI(I guess you might want to know how this kind of syntax has invented, too), I left my note on this syntax what I've used to answer similar question.


  1. In perspective of linguistics, the answer is "Well, no one wouldn't find out why if creator never say the reason."(Just think about arbitrariness)

  2. If we trace the origin of this syntax, we would reach to Algol 58, which also introduced function(and procedure) in the world. And if we go through CACM's Algol 58 report, we can find the reason why they used those kind of syntax.

  1. The new language should be as close as possible to standard mathematical notation and be readable with little further explanation" - Page 9

"4. Function Declarations A function declaration declares a given expression to be a function of certain of its variables. Thereby, the declaration gives (for certain simple functions) the computing rule for assigning values to the function (cf. functions) whenever this function appears in an expression. " Page 18

$\endgroup$
4
  • $\begingroup$ (The answer to Why… is yes…?!) $\endgroup$
    – greybeard
    Commented Feb 16, 2020 at 23:01
  • $\begingroup$ @greybeard Oops, sorry, I just slept only 1h in both Sunday and Saturday, All the characters are flying in front of me now. I'll edit my answer after taking a sleep.. $\endgroup$ Commented Feb 16, 2020 at 23:08
  • $\begingroup$ Hello to all answerers: I now give 100rep bounty to improve details as this question was fully changed after it was merged with my new, better question which includes more accurate terminology, is more exampled and more carefully worded. I invite to consider edit your answers per the updates in question; I know this might seem sisyphic, but I think it would be helpful for future readers and will help you help me also. I have explained in the bounty message the whole mess behind this merging. So, for you consideration. No irreverence intended. $\endgroup$
    – user115711
    Commented Feb 19, 2020 at 1:53
  • $\begingroup$ FORTRAN and COBOL came well before Algol 58, and both use the f(x, y) notation for calls. $\endgroup$
    – vonbrand
    Commented Feb 29, 2020 at 1:10
2
+50
$\begingroup$

Why, in programming languages in general, must function declarations be followed by a parameter set ...

There are many programming languages and all of them work differently; nothing is "in general".

"mex functions" in Matlab for example do not have a possibility to define the number (or data types) of the required parameters; the function itself must check if the number of parameters is correct.

... external to the sub-routine scope?

why ... even if the parameter set ... are both empty.

Many modern programming languages are influenced by "C", which is influenced by "BCPL". For this reason the syntax of such languages uses many elements that are found in "C" or in "BCPL".

"C" requires declaring the function arguments after the function name and therefore the other programming languages also require that. "C" requires declaring local variables "in the sub-routine scope" and therefore the other programming languages also require that.

"Pascal" would be an example of a programming language that is not influenced by "C".

The following "Java" functions:

int myFunction()
{
    typedef int aType;
    aType a = anotherFunction();
    return a + 5;
}

int secondFunction(int a)
{
    return aThirdFunction(a+1);
}

... would look the following way in Pascal:

function myFunction: integer;
  type
    aType = integer;
  var
    a: aType;
  begin
    a := anotherFunction;
    myFunction := a + 5;
  end;

function secondFunction(a: integer): integer;
  begin
    secondFunction := aThirdFunction(a+1);
  end;

You can see that in "Pascal" the declaration of local variables and local data types is not "inside the scope of a function" (how you call mixing code and variable declarations). Declaring variables and types "inside the scope of a function" seems to be an invention of "C" and therefore you will find this feature in programming languages that have been influenced by "C" but not in most other programming languages.

To me it is obvious that a programming language not allowing a variable declaration "inside the scope of a function" will also not allow a parameter declaration there.

You can also see that neither a function call nor a function declaration of a function that does not take parameters uses empty brackets in "Pascal".

I'm not absolutely sure but I have already seen programming languages (in the industrial environment) where the parameter declaration does not follow the function name directly - just like shown here:

function myFunction
  local_data_types
    myType = integer
  memory_information
    in_far_ram
  calling_information
    from_near_flash
  parameters
    myParam1 = integer
    myParam2 = integer
  code
    return myParam1 + myParam2
  end

However, the designers of such a programming language would take care that all the parameters must be declared at the same position (here: after the parameters keyword):

It shall be possible for a programmer to look at the function and to see the list of required parameters at once; a programmer who wants to call the function should not need to search the entire code for the parameters required.

In your original question you also asked why such syntax elements ...

... endured in many programming languages?

The reason for this is simple:

In many projects you have to work with different programming languages. Imagine some device (like a "smart" coffeemaker) with an Ethernet plug that can be controlled via a web interface and via a PC program.

For programming the device you will need "C", for the web interface you'll need "JavaScript" and for the PC program you might need "C#".

Because you have to work with three programming languages in your project, you want the three programming languages to be as similar as possible because you don't want to learn three completely different languages.

For this reason a programming language which is completely different to other "widely used" programming languages would not be used by anybody. This seems to be the main reason why "Pascal" (which was quite popular in the 1990s) is only rarely used today.

$\endgroup$
0
$\begingroup$

This is (more or less) a legacy from C. In C (and most languages inheriting from it) you can declare a function (announce to the compiler what the function is all about), like:

int some_function(int, double, bool);

This announces that somewhere the function some_func will be defined (perhaps later in this file, perhaps in another file), and that some_func takes an int, a double and a bool as arguments, and returns an int. After that, you can call e.g. a = some_func(3, 17.3, true), and the compiler can check everything is OK with the call.

Somewhere else you define your function:

int some_func(int i, double d, bool b)
{
    if(b)
        return i * d;
    else
        return d - i;
}

The { ... } is the body of the function, the code executed if it is called.

It is allowed to have functions that take no arguments, and it is also allowed to have functions that do nothing. Both uses do make sense: A function that just retrieves some information from it's environment doesn't require arguments; functions that do nothing can be used as placeholders while you flesh out the program, or be alternatives to be called when nothing is to be done. So it is legal to declare:

int f();

Modern --since ANSI-- C usage explicitly states there are no arguments, nowadays the above says f is a function without detailing arguments:

int f(void);

then you can define:

int f()
{
}

or:

int f(void)
{
}

In the particular case of C (and close family) languages, you can declare:

int i, a[5], *p, f();

saying that i is an integer, a is an array (of 5 integers), p is a pointer to an integer, f is a function returning an integer. In the case of f, no further details are given. The various decorations specify what kind of object is being declared. Other languages use different syntax, in Pascal(-family) languages you'd say something like:

 var i: integer, array[0..4] of integer,
     p: ^integer;
 function f; forward;

where again f is just being declared (thus the forward) as a function with no arguments, it must be defined somewhere later, somewhat like:

function f;
  begin
    return 42
  end;

In Scheme (and other Lisp-familly languages) you define a variable as:

(define a)

if you want to give it a value, you'd say:

(define b 42)

while a function is just a variable that happens to have a function as value:

(define f
   (lambda (x y)
      (+ x y)))

which you then call like (f 3 4) (yes, parenthesis outside).

More in general, programming languages are rarely clean, completely rational constructions. Older languages (that have seen much use, and thus evolution) have changed and normally include obsolete constructions for the sake of backwards compatibility (asking everybody to rewrite tons of existing, working code just for the sake of a language change would create riots), some die-hard traditionalists will insist in using them even if better alternatives are available. New languages inherit from older ones, often including endearing quirks and inconsistencies.

$\endgroup$
4
  • 1
    $\begingroup$ Might be worth noting that other languages have different syntaxes (looking at you, Lisp and ML/Haskell families ) $\endgroup$ Commented Feb 16, 2020 at 15:50
  • $\begingroup$ @D.BenKnoble, no knowledge about ML/Haskell around here, sorry. Thanks for the nudge! $\endgroup$
    – vonbrand
    Commented Feb 16, 2020 at 18:05
  • 1
    $\begingroup$ np; in SML, for example, you can have fun add a b = a + b. Then add is the function, and add 4 is partial application, and add 4 5 is what you would expect. No parens required (unless you want add (add 1 2) 3). $\endgroup$ Commented Feb 16, 2020 at 19:25
  • $\begingroup$ Hello to all answerers: I now give 100rep bounty to improve details as this question was fully changed after it was merged with my new, better question which includes more accurate terminology, is more exampled and more carefully worded. I invite to consider edit your answers per the updates in question; I know this might seem sisyphic, but I think it would be helpful for future readers and will help you help me also. I have explained in the bounty message the whole mess behind this merging. So, for you consideration. No irreverence intended. $\endgroup$
    – user115711
    Commented Feb 19, 2020 at 1:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.