'void' : bug or feature?

P

Peter Oliphant

I just found out the following code compiles:

ref class ClassA
{
public:
ClassA()
{
x = 0 ;
X_To_1( ) ;
void X_To_2( ) ; // ****
Console::WriteLine( "x = {0}", x ) ; // "x = 1"
}

~ClassA() {}

private:
void X_To_1() { x = 1 ; }
void X_To_2() { x = 2 ; }

private:
int x ;
} ;

Note the line indicated by the asterisks above begins with a 'void'. What
this does is cause this line of code to be skipped. Hence, after the
constructor runs, x = 1 and not x = 2. Is this a bug or a feature?

The way I found this is I copy-and-pasted the function declaration to the
code and didn't remove the 'void' from in front. So it's an easy trap to
fall into...

[==P==]
 
T

Tamas Demjen

Peter said:
void X_To_2( ) ; // ****

What this does is cause this line of code to be skipped.

It simply declares the function, and does nothing else.

Tom
 
H

Holger Grund

Peter Oliphant said:
I just found out the following code compiles:

ref class ClassA
{
public:
ClassA()
{
x = 0 ;
X_To_1( ) ;
void X_To_2( ) ; // ****
Console::WriteLine( "x = {0}", x ) ; // "x = 1"
}
[..]
Note the line indicated by the asterisks above begins with a 'void'. What
this does is cause this line of code to be skipped. Hence, after the
constructor runs, x = 1 and not x = 2. Is this a bug or a feature?
The indicated line is simply a function declaration. Function scope
function declarations introduce functions from the nearest containing
namespace scope into the lexical scope. In your example the
declaration introduces the global
void X_To_2() function.

You could write
void X_To_2(); // declares ::X_To_2();
X_To_2(); // calls ::X_To_2();
....
}; // end of ref class ClassA

void X_To_2(){ //..}

Your member function declaration is in a different non-overlapping
scope. They are completely unrelated.
The way I found this is I copy-and-pasted the function declaration to the
code and didn't remove the 'void' from in front. So it's an easy trap to
fall into...
There's another common pitfall. Function declarations vs local variable
with initializers:

struct Y{}; struct X{ X(const Y&);};
void foo() {
// Want to construct an X with a default constructed Y into variable x
X x( Y() );
// however, this declares a function x which returns an X and takes a
// parameter of type Y() which is adjusted to Y(*)(), i.e.
// a function pointer taking no arguments and returning a Y

-hg
 
P

Peter Oliphant

Interesting. Why is it legal to declare function in the middle of a method?
What purpose does this have? Can I define a whole method inside the code for
another method? Something like:

void MethodA()
{
// code
void MethodB() { /* code */}
//code
MethodB() ; // call
// code
}

If this is possible, what is it used for? Why wouldn't it be better to
define MethodB totally external to MethodA (but still in the same class)? I
assume this would mean that ONLY MethodA has access to it ala scoping rules
(i.e., it is a 'local method' to MethodA)...

If it's not possible, why is declaring a method in the middle of another
method's code legal?

IMHO, this is a case where the benefit for adding functionality is
outweighed by the side-effect of the pitfalls it introduces...

[==P==]

Holger Grund said:
Peter Oliphant said:
I just found out the following code compiles:

ref class ClassA
{
public:
ClassA()
{
x = 0 ;
X_To_1( ) ;
void X_To_2( ) ; // ****
Console::WriteLine( "x = {0}", x ) ; // "x = 1"
}
[..]
Note the line indicated by the asterisks above begins with a 'void'. What
this does is cause this line of code to be skipped. Hence, after the
constructor runs, x = 1 and not x = 2. Is this a bug or a feature?
The indicated line is simply a function declaration. Function scope
function declarations introduce functions from the nearest containing
namespace scope into the lexical scope. In your example the
declaration introduces the global
void X_To_2() function.

You could write
void X_To_2(); // declares ::X_To_2();
X_To_2(); // calls ::X_To_2();
...
}; // end of ref class ClassA

void X_To_2(){ //..}

Your member function declaration is in a different non-overlapping
scope. They are completely unrelated.
The way I found this is I copy-and-pasted the function declaration to the
code and didn't remove the 'void' from in front. So it's an easy trap to
fall into...
There's another common pitfall. Function declarations vs local variable
with initializers:

struct Y{}; struct X{ X(const Y&);};
void foo() {
// Want to construct an X with a default constructed Y into variable x
X x( Y() );
// however, this declares a function x which returns an X and takes a
// parameter of type Y() which is adjusted to Y(*)(), i.e.
// a function pointer taking no arguments and returning a Y

-hg
 
P

Peter Oliphant

Oh yeah, one more thing:

Are you sure about this? Note that all definitions and even usages of
X_To_2() are entirely contained inside the scope of ClassA's definition.
Further, one 'version' of MethodB is a *private* method of ClassA, the other
a 'local method' to the public ClassA constructor (e.g., if I create a
'local variable' in a constructor it is not global). Why then would either
version be global?

I assume the linker doesn't complain about methods and functions declared
and not defined, IF they are never used. Otherwise I have even more
questions... ; )

[==P==]

Holger Grund said:
Peter Oliphant said:
I just found out the following code compiles:

ref class ClassA
{
public:
ClassA()
{
x = 0 ;
X_To_1( ) ;
void X_To_2( ) ; // ****
Console::WriteLine( "x = {0}", x ) ; // "x = 1"
}
[..]
Note the line indicated by the asterisks above begins with a 'void'. What
this does is cause this line of code to be skipped. Hence, after the
constructor runs, x = 1 and not x = 2. Is this a bug or a feature?
The indicated line is simply a function declaration. Function scope
function declarations introduce functions from the nearest containing
namespace scope into the lexical scope. In your example the
declaration introduces the global
void X_To_2() function.

You could write
void X_To_2(); // declares ::X_To_2();
X_To_2(); // calls ::X_To_2();
...
}; // end of ref class ClassA

void X_To_2(){ //..}

Your member function declaration is in a different non-overlapping
scope. They are completely unrelated.
The way I found this is I copy-and-pasted the function declaration to the
code and didn't remove the 'void' from in front. So it's an easy trap to
fall into...
There's another common pitfall. Function declarations vs local variable
with initializers:

struct Y{}; struct X{ X(const Y&);};
void foo() {
// Want to construct an X with a default constructed Y into variable x
X x( Y() );
// however, this declares a function x which returns an X and takes a
// parameter of type Y() which is adjusted to Y(*)(), i.e.
// a function pointer taking no arguments and returning a Y

-hg
 
B

Bo Persson

Peter Oliphant said:
Interesting. Why is it legal to declare function in the middle of a
method?

It is legal to put declarations in the middle of a function, like "int
i;".

Declaring a functions is just not ruled out.
What purpose does this have? Can I define a whole method inside the
code for another method?

Nested functions are not allowed. You could declare a class though
(with members functions).

[snip]
If this is possible, what is it used for?

Who says it's any good? :)

It is just not forbidden.
Why wouldn't it be better to define MethodB totally external to
MethodA (but still in the same class)?

Of course.
If it's not possible, why is declaring a method in the middle of
another method's code legal?

Just because it is not illegal.
IMHO, this is a case where the benefit for adding functionality is
outweighed by the side-effect of the pitfalls it introduces...

Sure. Everyone agrees on this one.

If it hadn't been this way in C for decades, it would never have
appeared in C++.


Bo Persson

ref class ClassA
{
public:
ClassA()
{
x = 0 ;
X_To_1( ) ;
void X_To_2( ) ; // ****
Console::WriteLine( "x = {0}", x ) ; // "x = 1"
}
[..]
 
T

Tamas Demjen

Peter said:
Are you sure about this?

Yes, it is absolutely positively a function declaration.
Why then would either version be global?

If you declare a function outside of a class declaration, it is global.
It declares a global function "void X_To_2()", which is never implemented.
I assume the linker doesn't complain about methods and functions declared
and not defined, IF they are never used. Otherwise I have even more
questions... ; )

If you start calling it, the linker will complain, otherwise it won't.
There's no such thing as linker warning indicating dead function
declarations. The compiler can not possibly know if your function will
be used or not, because it doesn't see the whole picture, only one unit
at a time. The linker doesn't know it either, because it only knows
about functions actually being called.

Tom
 
O

Ondrej Spanel

Peter Oliphant said:
Interesting. Why is it legal to declare function in the middle of a
method? What purpose does this have? Can I define a whole method inside
the code for another method? Something like:

void MethodA()
{
// code
void MethodB() { /* code */}
//code
MethodB() ; // call
// code
}

You can define almost anything inside of the function, but not a function.
You can use operator () and define functor instead, if you want. (This could
be quite handy sometimes, having the functor defined near where it is used -
unfortunatelly C++ standard currently does not allow template instantiation
with such local types).

void MethodA()
{
class MethodB
{
public:
void operator () () const
{
// code goes here
}
};
//code
MethodB()() ; // construct and call in one line
MethodB b();
b() ; // another way to call
}
If it's not possible, why is declaring a method in the middle of another
method's code legal?

Sometimes you may want some external function to be visible only in some
particular function, sometimes you might want to do this just because you
are lazy ;) and do not want to scroll outside of the long function, body. It
is not a common practice though, and I think it is not even a good practice,
because it can easily break modularity of your code by creating hidden
dependencies.

Regards
Ondrej

If this is possible, what is it used for? Why wouldn't it be better to
define MethodB totally external to MethodA (but still in the same class)?
I assume this would mean that ONLY MethodA has access to it ala scoping
rules (i.e., it is a 'local method' to MethodA)...


IMHO, this is a case where the benefit for adding functionality is
outweighed by the side-effect of the pitfalls it introduces...

[==P==]

Holger Grund said:
Peter Oliphant said:
I just found out the following code compiles:

ref class ClassA
{
public:
ClassA()
{
x = 0 ;
X_To_1( ) ;
void X_To_2( ) ; // ****
Console::WriteLine( "x = {0}", x ) ; // "x = 1"
}
[..]
Note the line indicated by the asterisks above begins with a 'void'.
What
this does is cause this line of code to be skipped. Hence, after the
constructor runs, x = 1 and not x = 2. Is this a bug or a feature?
The indicated line is simply a function declaration. Function scope
function declarations introduce functions from the nearest containing
namespace scope into the lexical scope. In your example the
declaration introduces the global
void X_To_2() function.

You could write
void X_To_2(); // declares ::X_To_2();
X_To_2(); // calls ::X_To_2();
...
}; // end of ref class ClassA

void X_To_2(){ //..}

Your member function declaration is in a different non-overlapping
scope. They are completely unrelated.
The way I found this is I copy-and-pasted the function declaration to
the
code and didn't remove the 'void' from in front. So it's an easy trap to
fall into...
There's another common pitfall. Function declarations vs local variable
with initializers:

struct Y{}; struct X{ X(const Y&);};
void foo() {
// Want to construct an X with a default constructed Y into variable x
X x( Y() );
// however, this declares a function x which returns an X and takes a
// parameter of type Y() which is adjusted to Y(*)(), i.e.
// a function pointer taking no arguments and returning a Y

-hg
 

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

Top