Do Class Functions/Variables Have to Be Declared Before Being Used

Do class functions/variables have to be declared before being used?

Good question; I've relied on that feature for years without thinking about it. I looked through several C++ books to find an answer, including Stroustrup's The C++ Programming Language and The Annotated C++ Reference Manual, but none acknowledge or explain the difference. But, I think I can reason through it.

The reason, I believe, that your example works is that the bodies of your test and printout aren't truly where they appear in your file. The code

class MyClass {
void someFun() {
x = 5;
}
int x;
};

...which appears to violate the rule of having to declare variables before you use them, is actually equivalent to:

class MyClass {
void someFun();
int x;
};

void MyClass::someFun() {
x = 5;
}

Once we rewrite it like that, it becomes apparent that the stuff inside your MyClass definition is actually a list of declarations. And those can be in any order. You're not relying on x until after it's been declared. I know this to be true because if you were to rewrite the example like so,

void MyClass::someFun() {
x = 5;
}

class MyClass {
void someFun();
int x;
};

...it would no longer compile! So the class definition comes first (with its complete list of members), and then your methods can use any member without regard for the order in which they're declared in the class.

The last piece of the puzzle is that C++ prohibits declaring any class member outside of the class definition, so once the compiler processes your class definition, it knows the full list of class members. This is stated on p.170 of Stroustrup's The Annotated C++ Reference Manual: "The member list defines the full set of members of the class. No member can be added elsewhere."

Thanks for making me investigate this; I learned something new today. :)

Why is the 'Declare before use' rule not required inside a class?

That's because member functions are compiled only after the whole class definition has been parsed by the compiler, even when the function definition is written inline, whereas regular functions are compiled immediatedly after being read. The C++ standard requires this behaviour.

Why do functions need to be declared before they are used?

How do you propose to resolve undeclared identifiers that are defined in a different translation unit?

C++ has no module concept, but has separate translation as an inheritance from C. A C++ compiler will compile each translation unit by itself, not knowing anything about other translation units at all. (Except that export broke this, which is probably why it, sadly, never took off.)

Header files, which is where you usually put declarations of identifiers which are defined in other translation units, actually are just a very clumsy way of slipping the same declarations into different translation units. They will not make the compiler aware of there being other translation units with identifiers being defined in them.

Edit re your additional examples:

With all the textual inclusion instead of a proper module concept, compilation already takes agonizingly long for C++, so requiring another compilation pass (where compilation already is split into several passes, not all of which can be optimized and merged, IIRC) would worsen an already bad problem. And changing this would probably alter overload resolution in some scenarios and thus break existing code.

Note that C++ does require an additional pass for parsing class definitions, since member functions defined inline in the class definition are parsed as if they were defined right behind the class definition. However, this was decided when C with Classes was thought up, so there was no existing code base to break.

variables that is used before declaration but declared after use

As much as I can perceive, the thing which is baffling you is the order of code in which it is declared. Have a look at below code:

class Program
{
public Program()
{
}

public void myFunc()
{
canIAccessIt = 10;
}

public int canIAccessIt = 0;
}

As in above code anyone from C language background (ignore class part which doesn't exist in C) might get into a thinking that myFunc function is trying to access a variable canIAccessIt even before it has been declared or has come into scope.

Scope of variables in C# .Net world doesn't work that way. A class level variable (aka member variable) gets associated with the instance of the object instead and comes into scope from the time the object is created till the time object is destroyed or garbage collected.

Like in the above case, one might think that canIAccessIt variable might not have come to life as it is declared below myFunc method. It is not so.

When my above code is compiled by C# compiler it becomes something like this in MSIL (Microsoft intermediate language) written inside your *.dll file which is the output of the C# project building process:

class Program
{
public int canIAccessIt;
public Program()
{
canIAccessIt = 0;
}

public void myFunc()
{
canIAccessIt = 10;
}
}

Note: The above MSIL code is just for your reference purpose so that you can understand it. MSIL code looks much more weird than this as it has to be understood by the CLR rather than a user or a programmer.

So for compiler it doesn't matter where the global variable is declared inside your class. As long as it is inside the opening({) and closing curly brace (}) of your class then its initialization will get moved inside the constructor of your class. Constructor of a class is the first method which gets called whenever you new-up a class instance. The moment it happens your variable will come to life (intantiated and initialized) and become in-scope to be used by myFunc method.

The only difference with i variable in your class is that it is static so its initialization will move the static constructor of your class rather than an instance constructor of your class. Life-time and scope of your i variable is associated with Type instance (aka static instance) of your class.

So whenever you initialize your class for the first time to be able to call your ReplaceCC method here is the sequence of events:

  1. Instance constructor gets called.
  2. Static constructor gets called - It initializes your static i variable.
  3. Then you call ReplaceCC method on the object instance when i is already instantiated and initialized.

You can also look at this answer which seconds my thoughts.

Does the order of declaring functions and methods in C++ matter

The order does matter. If you reference a function which has not been declared (just the signature and return type, no implementation) then the compiler will throw an error. The definition of your function can wait until link time. AFAIK, there is not implicit declaration in C++.

Usually you put the declarations of your functions in header files. Traditionally, the symbols exported by a translation unit (usually a stand-alone source file e.g., hello.cpp) will be made available through a similarly-named header file (e.g., hello.h). The implementation then follows in the source file. Every translation unit can then include header files from other translation units (e.g. other.h).

Every translation unit gets compiled individually (i.e. a source file such as hello.cpp; all #include preprocessing statements are replaced by the actual contents of the files to be included). At link time, the implementations of the functions in different translation units get linked together. If this linking step fails, then you can still encounter errors.

Why do I not have to forward declare functions or variables inside classes?

In C++, the order in which functions or variables are declared does
not matter at all. There is nothing wrong with calling functions that
are not declared yet. The same applies for variables.

... That's not at all true? You need to declare functions and variables before using them, otherwise the compiler will not be particularly happy with you.

EDIT In response to the edit, what you have shown is a very special case in which everything involved is internal to a class. In this particular case, you can use undeclared variable and function names. The only reason you can do this is because the compiler treats the class definition as one unit and reads through all of it before compiling. In general, however, you have to forward declare everything.

Why can I use a variable in a function before it is defined in Python?

To understand what is happening, one must understand the distinction Python makes between defining a function, and executing a function.

Definition vs Execution

When Python encounters a function definition, it compiles the function into a code object.

A code object is an internal structure Python uses to hold the bytecode associated with a specific executable block of code. It also holds other information Python needs to execute the bytecode such as constants and local variable names. The documentation gives a much more more extensive overview of what code objects are.

The code object is then used to construct a function object. The function object's code object is then used to execute the function when it is later called. Python would not execute the function, it would only compile the function into an object that could be used later for execution. The only time Python executes a function, is when the function is called.

Here is the relevant part from the documentation which mentions this:

A function definition is an executable statement. Its execution binds the function name in the current local namespace to a function object (a wrapper around the executable code for the function). This function object contains a reference to the current global namespace as the global namespace to be used when the function is called.

The function definition does not execute the function body; this gets executed only when the function is called.

Because of this distinction, Python cannot verify a name is actually defined until the function is called. Thus, you are allowed to use currently non-existent names in the function body. As long as the name is defined when the function is called, Python will not raise an error.

Here is an example. We define a function func that adds two variables together; a and b:

>>> def func():
... return a + b

As you can see Python raised no error. This is because it simply compiled func. It did not attempt to execute the function, so it does not see that a and b are not defined.

We can disassemble func's code object, and see what the bytecode looks like using the dis module. This will tell us more about what Python is doing:

>>> from dis import dis
>>> dis(func)
2 0 LOAD_GLOBAL 0 (a)
2 LOAD_GLOBAL 1 (b)
4 BINARY_ADD
6 RETURN_VALUE

Python encoded two LOAD_GLOBAL instructions in the byte-code. The arguments to the instructions are the variable names a and b respectively.

This shows that Python did see that we were attempting to reference two variables when compiling our function and created bytecode instructions to do so. But it does not attempt to actually execute the instructions, until the function is called.

Let's see what happens when we attempt to execute the bytecode for func by calling it:

>>> func()
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
func()
File "<pyshell#14>", line 2, in func
return a + b
NameError: name 'a' is not defined

As you can see, Python raised a NameError. This is because it attempted to execute the two LOAD_GLOBAL instructions, but discovered that the names where undefined in the global scope.

Now let's see what happens if we defined two variables a and b before calling func:

>>> a = 1
>>> b = 2
>>>
>>> func()
3

The reason the above worked, is because when Python was executing func's byte-code, it was able to find the global variables a and b, and used those to execute the function.

The same applies to the example is the question. When main was compiled, Python "saw" we were trying to call a variable named cube and generated an instruction to get the value of cube. But it did not attempt to find a callable object named cube until the instructions were executed. And by the time main's byte-code was executed(eg. main was called), a function named cube was defined, so Python did not raise an error.

If we try to call main before cube is defined however, we'll get a name error for the same reasons in the above example:

>>> def main():
... number = int(input('Enter a number: '))
... cubed_number = cube(number)
... print("The number cubed is: ", cubed_number)
...
>>> main()
Enter a number: 23
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
main()
File "<pyshell#22>", line 3, in main
cubed_number = cube(number)
NameError: name 'cube' is not defined

What about the class?

Python handles class definitions a bit differently from function definitions.

When Python encounters a class definition, it creates a code object for the class as with the function. However, Python also allows classes to have namespaces that are executed during the class definition. Python does not wait to execute the classes namespace because any variables defined should belong to the class. Thus, any names used inside of a classes name-space must be defined for usage during class-definition time.

The documentation for class definitions touches on this:

The class’s suite is then executed in a new execution frame (see Naming and binding), using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly function definitions.) When the class’s suite finishes execution, its execution frame is discarded but its local namespace is saved.

However, this does not apply to methods. Python treats undefined names in methods as with functions, and allows you to use them when defining the method:

>>> class Class:
... def method(self):
... return var
...
>>> var = 10
>>> cls = Class()
>>> cls.method()
10


Related Topics



Leave a reply



Submit