C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

The "variable definition vs. function declaration" problem

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards
View previous topic :: View next topic  
Author Message
Daryle Walker
Guest





PostPosted: Mon Jan 03, 2005 5:31 pm    Post subject: The "variable definition vs. function declaration" problem Reply with quote



[I was going to publish this here and on c.l.c++, but decided to put it
just in c.l.c++. Someone there suggested that I publish it here though.]

This is about the common confusion over:

CONFUSION := type-expression  identifier "(" (PART ("," PART)*)? ")"

PART := type-expression "(" identifier ")"

Within a function's (or member function's) definition, such constructs
are meant to be a variable definition with constructor call 99.99%[A] of
the time. However, compilers must always interpret it as a function
declaration, turning it into a no-op. Why must the compiler (almost)
always do the wrong thing here? Can we change the rules? The issues,
besides the lack of a real solution, include:

{1} Allowing function forward declarations within a function was a
carry-over from C. I say that this is unnecessary to keep any longer.
It has now become dangerous with the introduction of name spaces.

namespace daryle
{
int f()
{
double g( char ); // C doesn't have this scenario

return 5;
}
}

void h()
{
void k();
}

Quick, is "g" really "::daryle::g" or "::g"? Or does it use some form
of lookup?[B] Is the answer different for "k"? This feature is the
only one I know of where lexical containment does NOT mean compile-item
containment. (Dropping this misfeature could clear a way for actual
nested functions.) Does the current interpretation have any legitimate
use?

{2} The same parsing confusion happens outside of function definitions,
where it pits function prototypes against global objects. Here, we
actually need function declarations. We need some way of forcing the
"global object" case.

{3} As someone in the comp.lang.c++ version of this thread said,
compiler makers _still_ do not flag this problem (within function
definitions). Can any of them here give an explanation for that? There
would have to be two warning switches, one for any function declaration
within a function definition (default on), and another for function
declarations outside function definitions that seem to have excess
parentheses (default off). Sorry that the latter is fairly vague, but
the former should be very definitive to determine.

[A] 42.9% of statistics are made up
[B] What is the answer to this, anyway?

--
Daryle Walker
Mac, Internet, and Video Game Junkie
dwalker07 AT snet DOT net

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

Back to top
richard@ex-parrot.com
Guest





PostPosted: Wed Jan 05, 2005 3:48 pm    Post subject: Re: The "variable definition vs. function declaration" probl Reply with quote




Daryle Walker wrote:
Quote:
[I was going to publish this here and on c.l.c++, but decided to put
it
just in c.l.c++. Someone there suggested that I publish it here
though.]

This is about the common confusion over:

CONFUSION := type-expression identifier "(" (PART ("," PART)*)?
")"

PART := type-expression "(" identifier ")"

Within a function's (or member function's) definition, such
constructs
are meant to be a variable definition with constructor call 99.99%[A]
of
the time. However, compilers must always interpret it as a function
declaration, turning it into a no-op. Why must the compiler (almost)

always do the wrong thing here? Can we change the rules?

This breaks backwards compatibility, both with C and with current C++.
Just because most of the time, most people don't put function
declarations at block-scope, doesn't mean that no-one ever does.
Changing the rules *will* break existing code.

Quote:
namespace daryle
{
int f()
{
double g( char ); // C doesn't have this scenario

return 5;
}
}

void h()
{
void k();
}

Quick, is "g" really "::daryle::g" or "::g"?

g is ::daryle::g -- a block-scope function declaration declares the
function in the inner-most enclosing namespace scope.


Quote:
Is the answer different for "k"?

k is again declared at the inner-most enclosing namespace scope. This
time it is in the global namespace.

Quote:
This feature is the
only one I know of where lexical containment does NOT mean
compile-item
containment.

Friend declarations?

Quote:
(Dropping this misfeature could clear a way for actual
nested functions.)

It's arguable how useful it would be to be able to forward declare
nested (i.e. block-scope) functions. The current grammar would extend
to block-scope function *definitions* without difficulty. If you
allowed forward declarations of block-scope functions (breaking
compatibility with the existing language), would you allow them to
defined "out-of-line"?

class Class {
void outer() const;
};

void Class::outer() const {
int inner();
}

int void Class::outer() const::inner() {
return 42;
}

Finding a convenient syntax for this definition is likely to be
problematic.


Quote:
Does the current interpretation have any legitimate
use?

Yes. Resolving ambiguities in overload resolution:

// Two ambiguous overloads, perhaps from different headers in
// different parts of the program. Obviously good progamming
// techniques would minimise the likelyhood of this occuring.
void f( int = 0 );
void f( long = 0 );

int main() {
void f(int = 0);
f(); // f(int);
}

Or allowing code (perhaps templated in a header) to access an
implementation-detail without injecting the name into the applicable
namespace.

namespace library {
template <class T> void my_algorithm() {
void helper(); // don't make visible elsewhere
helper();
}
}

// In .cc file
namespace library {
void helper();
}


Quote:
{2} The same parsing confusion happens outside of function
definitions,
where it pits function prototypes against global objects. Here, we
actually need function declarations. We need some way of forcing the

"global object" case.

Extra parentheses can usually be used to resolve the ambiguity in
favour of an object declaration.

int f1( int() );
int f2(( int() ));

In this case f1 is a function return an int and taking one argument, a
pointer to a function returning an int and taking no arguments.
However, f2 is int initialised from a default-constructed int. I.e. f1
is a function, f2 is an object.

Quote:
{3} As someone in the comp.lang.c++ version of this thread said,
compiler makers _still_ do not flag this problem (within function
definitions).

Very often they do, simply for the reason that it is unusual to declare
an object and not then use it. So:

int main() {
int i(); // I meant to default-construct an integer

i = 42; // Error: i is a function
}

Of course, there are occasions when you do not get an error:

mutex my_mutex;

void f() {
scoped_lock s( mutex ); // Ooops forgot the 'my_'.
// code not using s.
}

I find the best way to avoid this is to program defensively -- whenever
I declare a scoped_lock object (as I meant to here), I would write

auto scoped_lock s( my_mutex );

That wat, if I accidentally omit the 'my_' prefix and so declare a
function, I will get an error about it being illegal for a function to
be declared 'auto'. Although I wouldn't usually advocate using the
auto keyword, this is one situation where I would usually try to use
it. (Especially given that the runtime errors resulting from the
missing locks might easily be overlooked, even if the library has a
good test suite.)

Quote:
Can any of them here give an explanation for that?

Lack of demand?

Quote:
There
would have to be two warning switches, one for any function
declaration
within a function definition (default on), and another for function
declarations outside function definitions that seem to have excess
parentheses (default off).

The latter is probably not what you want. Take this example

int f( int() );

-- it declares a function, f, returning int and taking one argument, a
pointer to a function returning int and taking no arguments. A clearer
way of declaring this (in my opinion) would be

int f( int (*)(void) );

This has more paretheses -- not fewer. Perhaps you are thinking about
older compilers (e.g. some versions of gcc before 3.4) where

int f(( int() ));

does not correctly disambiguate the declaration to be that of an
object. Surely, though, the correct solution here is to fix the
compiler? (As, indeed, was done.)

--
Richard Smith

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.