Parentheses in function calls

B

BartC

x = F (i + j) * k, y;

Does F take one or two parameters?

The signature for F will tell you many arguments it expects. But it's not
clear whether they are expected to be separated with commas or white-space
anyway:
Is the comma serving as an
argument separator (in which case F takes two arguments) or as a comma
operator (in which case F takes one argument)? If it's acting as the
comma operator, then which of the following sequences of operations is
the right one:

(i + j) * k is evaluted, y is evaluated, result of y is passed to
F,
result of F(y) is assigned to x
F(i + j) * k is evaluated, y is evaluated, result of y is assigned
to x

If the rules of C still apply, and F takes one argument, then the latter.
But comma-separated arguments, and comma operators, are not a good mix.
Or, even better:

x = F;

Does x get the result of calling F with no arguments, or does x get
the *address* of F?

If you can write F() as F, then you need another notation for the address of
F:

x = &F;
And it turns out that it's *not* easy to implement; the grammar and
associated parser become more complicated because now you've
introduced some ambiguity in the expression

Just about anything is possible to parse. Even some ambiguity can be
tolerated, provided there is also a way of writing exactly what is intended.
 
B

BartC

Scott Fluhrer said:
That makes parsing a bit tricky unless you tweak the rules for expressions
as well. For example off the top of my head, how would you parse:

if a - b * c + d;

Would that be:

if (a) -b * c + d;
if (a-b) *c + d;
if (a - b*c) +d;

I'm sure you can come up with a plausible rule (maximal or minimal munch,
say), but how would that plausible rule fare with real examples?

I'm not sure the OP was being that serious, but he's talking about removing
parentheses such as these, not doing away with precedence:

if (a) b;
while (a) b;

Other languages might write these as 'if a then b', 'if a: b', 'while a do',
and so on. (And C might use: 'if a {b;})

It's certainly possible, if you were to mostly do away with current C
syntax.
 
L

Lew Pitcher

Eric Sosman said:
x = F (i + j) * k, y;

Does F take one or two parameters?

The signature for F will tell you many arguments it expects.[...]

int F(int, ...);

Your move ... ... ...

A function F just consumes as many argument terms as are necessary.

With a variable argument list, it will consume all that are available.

Some ambiguity can be dealt with with parentheses, around the entire
function (not just around it's arguments). Here, both F and G take
variable arguments:

F a b G c d e f means F(a,b, G(c,d,e,f)

F a b (G c d) e f means F(a,b, G(c,d), e,f)
[snip]

I gotta say that this proposal doesn't pass muster. The purpose of a high
level computer language is to accomodate the /programmer/ and make it
easier to develop and maintain programs. IMHO, this change would make C
into a "write-only" language, and would radically complicate
the /maintenance/ of C language programs.

Without your "explanation", I wouldn't have been able to determine that
F a b G c d e f
meant
F(a,b,G(c,d,e,f))
and would have read it as
F(a,b,G,c,d,e,f)

Consider the case of any function which takes, as an argument, a pointer to
a function. Unless you also propose to change how C treats function names
as pointers, your proposal leads to some ambiguity.

Given
void G(a,b){ return; }
does
F a b c G d e f
mean
F(a,b,G(d,e),f)
or does it mean
F(a,b,G,d,e,f)
?

The prototype for F() will tell the /compiler/ which to read. Hopefully,
the /programmer/ is sharp enough to spot that prototype as well. But,
probably not. And even so, there is enough chance that the programmer will
misunderstand the invocation, even with the prototype in plain sight; such
is the nature of professional maintenance programming.
 
J

John Bode

x = F (i + j) * k, y;
Does F take one or two parameters?
The signature for F will tell you many arguments it expects.[...]
int F(int, ...);
Your move ... ... ...

A function F just consumes as many argument terms as are necessary.

How would you encode that into the grammar, though? You couldn't
successfully parse expressions like

F a, b

based on syntax alone.
With a variable argument list, it will consume all that are available.

Some ambiguity can be dealt with with parentheses, around the entire
function (not just around it's arguments). Here, both F and G take variable
arguments:

F a b G c d e f        means F(a,b, G(c,d,e,f)

F a b (G c d) e f      means F(a,b, G(c,d), e,f)

With the comma operator, it's simplest to give it higher priority than
'space':

F a b,c d              means F(a,(b,c),d)

Yuk. Now whitespace becomes significant.
Where the argument separator is also a comma, it's best to mix these with
parentheses:

F a,b,c,d  might become: F a,(b,c),d  or (F a,b,c),d

Although when F is known to take two arguments, then F a,b,c,d can just mean
F(a,b),c,d.

So, assume a function F that consumes a single argument. Given the
expression

F (i + j) * k

how do we determine whether it should be evaluated as

F ((i + j) * k)

or

(F (i + j)) * k

The OP's point was that parens around function arguments added
"clutter" to the code, and that they should only be used to establish
precedence. But to successfully parse expressions like the one above,
you need just as many parens as before; you really haven't saved
yourself anything in the end.
 
B

BartC

John Bode said:
How would you encode that into the grammar, though? You couldn't
successfully parse expressions like

F a, b

based on syntax alone.

I did actually partly test the idea, but using comma separators (and
ignoring comma operators which would have taken a bit longer, but would be
treated similarly to ordinary ops).

I don't like not having just white-space between expression terms, but I
believe it's possible.
So, assume a function F that consumes a single argument. Given the
expression

F (i + j) * k

how do we determine whether it should be evaluated as

F ((i + j) * k)

or

(F (i + j)) * k

I don't see the problem; the (i+j)*k is just one term, and therefore one
argument. My test program turned:

F(i+j)*k;

into this syntax tree (if you'll excuse the extra junk):

00008 ?--------1 Function 'f' <fn>??
00008 ?------------1 Binopc mul (*)
00008 ?----------------1 Binopc add (+)
00008 ?--------------------1 Name 'i' <Name>??
00008 ?--------------------2 Name 'j' <Name>??
00008 ?----------------2 Name 'k' said:
precedence. But to successfully parse expressions like the one above,
you need just as many parens as before; you really haven't saved
yourself anything in the end.

Probably; I'm not advocating this syntax, just showing it's probably
feasible.
 
B

BartC

Lew Pitcher said:
On August 31, 2010 05:39, in comp.lang.c, (e-mail address removed) wrote:
F a b G c d e f means F(a,b, G(c,d,e,f)

F a b (G c d) e f means F(a,b, G(c,d), e,f)
[snip]

I gotta say that this proposal doesn't pass muster. The purpose of a high
level computer language is to accomodate the /programmer/ and make it
easier to develop and maintain programs. IMHO, this change would make C
into a "write-only" language, and would radically complicate
the /maintenance/ of C language programs.

Well, I'm not suggesting changing C to this; I happen to like brackets
around function arguments. But I don't think it's impossible to achieve.
Without your "explanation", I wouldn't have been able to determine that
F a b G c d e f
meant
F(a,b,G(c,d,e,f))
and would have read it as
F(a,b,G,c,d,e,f)

Consider the case of any function which takes, as an argument, a pointer
to
a function. Unless you also propose to change how C treats function names
as pointers, your proposal leads to some ambiguity.

I suggested elsewhere that this would need syntax such as &F or &G, where a
pointer to a function is needed.
Given
void G(a,b){ return; }
does
F a b c G d e f
mean
F(a,b,G(d,e),f)
or does it mean
F(a,b,G,d,e,f)
?

The prototype for F() will tell the /compiler/ which to read. Hopefully,
the /programmer/ is sharp enough to spot that prototype as well. But,
probably not. And even so, there is enough chance that the programmer will
misunderstand the invocation, even with the prototype in plain sight; such
is the nature of professional maintenance programming.

How well does it work with Perl? I don't think it would be that bad in real
code; it would be up to the programmer to keep the code clear. But I don't
see any problem with:

fopen "input", "rb";
printf "A,B = %d, %d\n", a, b;

(Ie. when using procedure rather than function calls.)

And anyway local coding styles could just insist on the parentheses.
 
J

John Bode

Your opinion is wrong. There are high level languages that have no problem with
this kind of syyntax. However they are not C. Changing the syntax in this way
means the language would no longer be C.

Exactly. You could not retrofit this kind of feature onto the
existing C language grammar; the point I was trying to make to the OP
was that to do what he wanted would be a helluva lot more work than
was worth it.
 
N

Nobody

Your opinion is wrong. There are high level languages that have no
problem with this kind of syyntax.

ML and Haskell use juxtaposition for function application. However:

1. They don't support variadic functions.

2. Technically, they don't support functions of more than one argument. In
practice, a "function with more than one argument" means either:

a) a function whose argument is a tuple, e.g.:

f (x, y) = x + y

This isn't quite the same thing as a multi-argument function in e.g. C, as
tuples are values in their own right, so you can do e.g.:

a = (x, y)
r = f a

b) a "curried" function, e.g.:

f x y z = x + y + z

A curried function accepts one argument and returns a function which
accepts the remaining argument(s). So given the above definition, the
expression:

r = f x y z

is parsed as:

r = ((f x) y) z

which, in C syntax, would be:

r = f(x)(y)(z)

In practice, curried functions are more common, as they can be partially
applied. E.g.:

f x y = x + y
map (f 3) [1,2,3]
=> [4,5,6]

3. Function application has higher precedence than any operator, so:

a b c + d e f

is parsed as:

(a b c) + (d e f)

This is exploited by Haskell's $ operator, which performs function
application:

f $ x = f x

While juxtaposition has the highest precedence, the $ operator has the
lowest precedence. It is commonly used to avoid a pile-up of closing
parentheses in deeply-nested applications e.g.:

a (b (c (d (x + y))))

can be written as:

a $ b $ c $ d $ x + y

Alternatively, you could use the function composition operator ("o" in ML,
"." in Hasell) to create a single function representing the entire
"pipeline", and apply that:

(a . b . c . d)(x + y)

Haskell isn't any harder to read than C when you're familiar with it.
However, I think that the rule of function application having higher
precedence than any infix operator is central to this. If you had
operators with precedence both above and below that of function call, it
would make the language much harder to read.

Conversely, given how common it is to nest function application, requiring
parentheses would make the language look like Lisp.
 
S

Shao Miller

John said:
Exactly. You could not retrofit this kind of feature onto the
existing C language grammar; the point I was trying to make to the OP
was that to do what he wanted would be a helluva lot more work than
was worth it.

I don't understand. I would _not_ enjoy the removal of our currently
function call operator one bit. But if the language changes, the
language changes. If the original poster convinces a majority of the
relevant people of the benefit and the suggestion is standardized, then
I fail to understand why that would not be C. Perhaps you both mean "C
circa 2010"?
 
K

Keith Thompson

Shao Miller said:
I don't understand. I would _not_ enjoy the removal of our currently
function call operator one bit. But if the language changes, the
language changes. If the original poster convinces a majority of the
relevant people of the benefit and the suggestion is standardized, then
I fail to understand why that would not be C. Perhaps you both mean "C
circa 2010"?

I don't believe it could be done without breaking existing code,
something the committee tries very hard to avoid doing.

Defining the relevant changes while *minimizing* the breaking of
existing code would be a large task (with, IMHO, little benefit).

Surely there is some set of changes to the C standard that, even if
endorsed by the committee, would make the language "no longer C".
For example, "Delete Replace sections 1 through 7 and Annexes A
through J of the C99 standard and replace them with the text of
the Fortran standard".

The proposal to drop the use of parentheses as part of the syntax
of function calls obviously isn't that radical, but it's radical
enough and IMHO not C-like.
 
E

Ersek, Laszlo

I don't understand. I would _not_ enjoy the removal of our currently
function call operator one bit. But if the language changes, the language
changes. If the original poster convinces a majority of the relevant people
of the benefit and the suggestion is standardized, then I fail to understand
why that would not be C. Perhaps you both mean "C circa 2010"?

(This is the second thread today that I start to read at the end. Sorry!)

I believe it would not be C because the "function" notion would change
completely, throwing away all tradition.

I fiddled with Haskell very shortly when it was the rage on reddit a few
years(?) ago, and the idea is "currying" (I think).

http://en.wikipedia.org/wiki/Currying

In short, instead of defining a function taking N values of different
types (that is, an N-component tuple) and returning yet another value of
yet another type, you define the function as taking only the first
component of the original tuple, and returning another function, which
takes one less arguments. For the returned function, you apply the same
recursion immediately.

In vague Haskell-like sytnax (as I said, I only scratched the surface -- I
stopped as soon as I *thought* I understood monads), the original function
signature ("prototype") is

f :: (type1, type2, type3) -> type4

This is the "C style" declaration, and the "C semantics" go with it:
evaluate all arguments before the call (in unspecified order), call the
function, return the return value. You "call" this as "f (a, b, c)" even
in Haskell, though in Haskell -- to say the least -- (a, b, c) is a single
tuple, not "three arguments". (Sorry, I really can't recall the correct
Haskell syntax, perhaps look at
<http://en.wikibooks.org/wiki/Haskell/Lists_and_tuples#Tuples> if
interested.)

Contrast:

f1 :: type1 -> type2 -> type3 -> type4

or, fully parenthesized:

f1 :: type1 -> (type2 -> (type3 -> type4)))

You "call" this as

f1 a b c

It is equivalent to the following, fully-parenthesized form:

(((f1 a) b) c)

"f1 a" is a "partial application":

f1 a :: type2 -> (type3 -> type4))

and so on:

f1 a b :: type3 -> type4

This is very alien from C -- there is no immediate way to write the
equivalent of "f1 a b" in C (that is, dynamically create a partial
application, which is itself a function), and even "f1 a b c" -- that
could correspond to the original f(a, b, c) call -- is not evaluated in
Haskell until needed.

http://en.wikipedia.org/wiki/Lazy_evaluation


Sometimes in Haskell, you *do* wish to write

g(h(i))

Haskell does have some syntactic sugar for that:

g $ h $ i

http://stackoverflow.com/questions/940382/haskell-difference-between-dot-and-dollar-sign


I believe the C syntax (with parentheses) reflects an idea very well. I
also believe the Haskell syntax (without parentheses) reflects another
idea very well. It's only that those two ideas are fundamentally
different.

lacos
 
B

BartC

Scott Fluhrer said:
I know. But, if you interpret
if a b;
as meaning (what is in the current C syntax as):
if (a) b;

then how should the compiler interpret
if a - b * c + d;

OK. Here I don't think it's possible to have one expression (the condition)
running into another expression (the body) without an intervening token. Or
more parentheses than are needed at present.

(This would also make separating function arguments problematic, if only
white space was used, because +,-,*,& for example would be ambiguous.
Fortunately the OP hasn't said anything yet about eliminating commas..)
 
B

BartC

BartC said:
.....
I'm not advocating this syntax, just showing it's probably feasible.

Thinking about it some more, C does give some special problems, in doing
away with parentheses around argument lists, that might not affect a simpler
language:

(1) Once a syntax F a,b,c is chosen, it's no longer possible to optionally
put parentheses around the arguments: F (a,b,c); as this will then look like
a single argument (in C, comma-operators; elsewhere, a tuple). (Making
backwards compatibility difficult)

(2) Using F a b c syntax (without commas) is just about possible, but there
are operators that can be either mono or binary that can make it difficult
to separate arguments: F a -b -c; can be 1,2 or 3 arguments.

(3) In C, () also acts as a dereferencing symbol for function pointers,
which would then need adding manually: either use the () only as a
dereference symbol, or *: f() a,b,c or *f a,b,c;

(4) This then leads to a problem with expressions involving function
pointers, eg: *f-a, which can be parsed two ways (as a function call with
one argument, or subtraction of one term from another). Although type
information would sort this out, this would be needed during parsing, not
always practical.

(5) C's comma operator, combined with a comma separator, are likely to clash
requiring extra parentheses resolve properly.

Apart from all that, there's no real reason why this shouldn't make it into
the next spec..
 
K

Keith Thompson

BartC said:
(3) In C, () also acts as a dereferencing symbol for function pointers,
which would then need adding manually: either use the () only as a
dereference symbol, or *: f() a,b,c or *f a,b,c;
[...]

No, () doesn't dereference function pointers. The expression preceding
the parentheses in a function call is of type pointer-to-function.

What would dereferencing a function pointer give you, the code for the
function? Yes, that might be meaningful in some non-C languages.
 
E

Eric Sosman

I'm not sure the OP was being that serious, but he's talking about
removing parentheses such as these, not doing away with precedence:

if (a) b;
while (a) b;

No: He was quite specifically talking about function calls, and
suggested that the parentheses around argument lists were unnecessary.
In follow-ups, it became clear he was just indulging an idle fancy
and had not given the idea any serious thought at all.
 
S

Seebs

Apart from all that, there's no real reason why this shouldn't make it into
the next spec..

I entirely agree.

"Apart from that, Mrs. Lincoln, how did you like the play?"

-s
 
B

BartC

Keith Thompson said:
BartC said:
(3) In C, () also acts as a dereferencing symbol for function pointers,
which would then need adding manually: either use the () only as a
dereference symbol, or *: f() a,b,c or *f a,b,c;
[...]

No, () doesn't dereference function pointers. The expression preceding
the parentheses in a function call is of type pointer-to-function.

Yes. And dereferencing it will call the function. C needs () or (arglist)
for this. If () is not mandatory, then *fn could do the job.
What would dereferencing a function pointer give you, the code for the
function? Yes, that might be meaningful in some non-C languages.

C doesn't have this concept. You can either get the address of a function,
or evaluate it (ie. call the function).
 
B

BartC

Eric Sosman said:
No: He was quite specifically talking about function calls, and
suggested that the parentheses around argument lists were unnecessary.

I was referring to this:
 
B

Ben Bacarisse

BartC said:
Keith Thompson said:
BartC said:
(3) In C, () also acts as a dereferencing symbol for function pointers,
which would then need adding manually: either use the () only as a
dereference symbol, or *: f() a,b,c or *f a,b,c;
[...]

No, () doesn't dereference function pointers. The expression preceding
the parentheses in a function call is of type pointer-to-function.

Yes. And dereferencing it will call the function. C needs () or
(arglist) for this. If () is not mandatory, then *fn could do the job.

I don't think you've expressed this very well. The () "operator" of a
function call does not need to dereference anything (though it may well
do so). The point is that F and F() are different in C but without ()s
in a call you need a way to distinguish between a call and a reference
to the function (which becomes a pointer, just like most mentions of
arrays do). I.e.

x = F;

is ambiguous -- it could be a call or an assignment of a function
pointer.

<snip>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top