Paren elision on nullary calls

Scott L. Burson Scott_member at pathlink.com
Wed Mar 22 17:01:59 PST 2006


In article <dvoeak$2gvi$1 at digitaldaemon.com>, Oskar Linde says...
>
>Scott L. Burson wrote:
>>  Similarly, I would discourage the use of the
>> ampersand to reify a function; I think the ampersand should at least be optional
>> (as indeed it is in C) -- I don't see anything in the docs that says it's
>> required, but you seem to use it in all the examples. 
>
>I guess the reason is that D allows function calling (property like) 
>without trailing parentheses (). Meaning func is identical to func() in 
>most cases. The ampersand is needed to distinguish function calls from 
>function references.

A bit of Pascal leaked in there, eh?  Wow, I can find nothing about this in the
docs.  Experimentation with DMD, however, confirms what you say.

Gotta say I think it's a bad idea.  Consider:

int f() { return 7; }

void main() {
printf("%d\n", f * 2);    // parens optional (`f' or `f()')
int function() ff = &f;   // `&' mandatory
printf("%d\n", ff() * 2); // parens mandatory
int function() fff = ff;  // `&ff' illegal
int function() g = function int() { return 8; };
// wrong: int function() g = &function int() { return 8;};
printf("%d\n", (function int() { return 9;})() * g()); // all parens mandatory
}

In short, there are two kinds of functions, and the syntax rules are different
for referring to and invoking the two kinds.  (I'm even having trouble coming up
with good terms for the two kinds, though I suppose you could go with "named"
and "anonymous".)  I think this is confusing, and an unfortunate wart on a
language that has otherwise done a great job at keeping the rules simple.

I urge you to consider making the rules for named and anonymous functions the
same.  I see three ways to do this:

(a) make parens always required for a function call, as they are in C, C++,
Java, and most other languages; then you can drop the `&'.

(b) always require the `&' when referring to a function without calling it, and
then allow empty parens to be elided for all 0-argument calls.

(c) drop the `&' but still allow the elision of empty parens; this requires the
compiler to disambiguate based on context.

My favorite is A, but I'm guessing you feel committed to allowing the elision,
so that will be a non-starter.

B is certainly workable but more than a little ugly, as the ampersand would now
be required in a number of places it is currently forbidden, including when
assigning a function literal to a function variable.

That leaves C.  Although it will complicate your front end a bit, it might not
be too bad, because you already have to deal with disambiguation of references
to overloaded functions:

void foo(int function() g) { ... }
int f() { ... }
int f(int x) { ... }
.. foo(&f) ...

It seems like a straightforward extension of this disambiguation mechanism to
decide whether the intention was to call the function or pass it.  On the other
hand, it leaves you figuring out what to do with cases like:

void foo(int i);
void foo(function int() f);
int g() { return ...; }
.. foo(g) ...

You could require the parens (`foo(g())') if the intention is to call `g' rather
than just to pass it, but that seems dangerous; if the first version of `foo'
were the only one that existed when the call `foo(g)' were written, and then the
second were added later, the meaning of `foo(g)' would change.  Probably better
just to outlaw such overloadings so the situation can't arise.

-- Scott





More information about the Digitalmars-d mailing list