Skip to the content of the web site.

Why declarations and no using?

IEEE Spectrum Magazine    MIT Technology Review    Wired Magazine    EDN Network    EE Times    Skeptic's Guide to the Universe

A number of students are aware that the following code works:

#include <iostream>

using namespace std;

int main() {
    cout << "Hello world!" << endl;
}

In fact, even this works:

#include <iostream>
#include <cmath>

using namespace std;

double W( double x ) {
    return abs( 3.0 - abs( 3.0*x ) );
}

int main() {
    double value;
    cout << "Enter a value: ";
    cin >> value;

    cout << "W(" << value << ") = " << W(value) << endl;
}

Thus, you may be wondering why we:

  • require you to use function declarations,
  • do not allow you to use the using keyword, and
  • have main() return 0.

Ultimately, we want you to be competent developers, not just fly-by-night programmers who can throw something together in 30 seconds and then have it fail the next day, month or year.

Function (and class) declarations

C++ does not always require function declarations, but function declarations are useful for the following reasons:

  1. Anyone reading your code can find all functions in one easy-to-read list of function declarations without having to read through the entire file.
  2. In the example above, because main() calls W(...), it is absolutely necessary that W(...) be declared or defined before main() is defined. Otherwise, if the compiler is not aware of W(...), its parameters and return type, it cannot deal with it in main(). Thus, without a list of function declarations, the programmer is always needing to ensure that all function definitions come in the appropriate order so that no function is ever called in any other function definition before that function is defined.
  3. In some cases, it is impossible to not declare functions, such as, if function M(...) calls function F(...), and vice versa.
  4. Sometimes, it makes no sense to have certain functions at the top of files, just because they are used by other functions. Small helper functions are better defined at the end of the file, while more critical functions are defined near the top.
  5. Also, trying to teach students about the correct "order" and exceptions to this is actually much more complicated. "All functions must be declared first." is a simple rule that parallels "All variables must be declared first." This simpler rule is always guaranteed to work, no matter what.
  6. In any library, functions are declared separately from where they are defined. The header file only contains function declarations. It is in the corresponding .cpp file that the functions are defined.
  7. A more subtle reason has to do with version control. Suppose a file contained two functions, f(...) and g(...), and suppose initially, neither function called the other, and thus, either function could be defined first. Suppose that f(...) was defined first. Revision control keeps track of all changes so that changes made to a source file can be tracked, just in case, for example, a new change introduces a new bug. Suppose you were making a change where f(...) now had to call g(...). If f(...) was defined first, the order of the two functions would have to be switched (alternatively, you could just add a function declaration for g(...), but if you didn't do this initially, you may not think of it here). If the change was to only one line of code, the apparent change would be very significant, and any subsequent developer trying to find what was actually changed may become rather frustrated: two large functions were moved around, but all their statements appear to be essentially the same, except for exactly one line. If the functions were all declared first, this change would be recorded as having modified exactly one line, and thus any developer can subsequently determine exactly what was modified.
  8. Finally, if you are showing off your source code to others (think interviewers) who are more experienced programmers, they will appreciate your style, rather than ask you why you are (in your current opinion) wasting both time and space.

The same goes for class declarations versus class definitions.

using

Next, you may be wondering why we do not allow you to use the statement

using namespace std;

in which case, you don't have to prefix cout and endl with std::. Again, for the same reasons that we make you declare all your functions:

  1. You would almost never use using in any developed code base. The entire point of namespaces is to prevent collisions of names. By using the using keyword, you are destroying that protection.
  2. Thus, once again, if you are showing your source code to someone else, they will appreciate that reason, as opposed to asking you why you are (in your current opinion) wasting time and space.

The purpose of this course is not teach you solely how to write simple and easy functions that solve trivial problems. We're trying to teach you programming habits that will benefit you when you begin to work in industry in larger programming environments with source trees that have source files numbering in the hundreds or thousands with cumulatively tens of thousands or even millions of lines of code.

If you would like to read a further discussion on not using the using operator, see stackexchange.com.

An acceptable use of using

What is acceptable is explicitly stating which items in a particular namespace you would like to use without the, in this case, std:: prefix.

#include <iostream>

// This ensures that only 'cout' and 'endl' may be used
// with the 'std::' prefix. For any other object, class, etc.,
// in the standard library, you must still prefix the name
// by 'std::'
using std::cout;
using std::endl;

int main();

int main() {
    cout << "Hello world!" << endl;

    return 0;
}

Returning 0 from main()

As for returning zero from main(), yes, C++ and a more recent version of the C standard does not require main() to return anything. Instead, the compiler will automatically include a return 0; statement if none is stated. However:

  1. Does it really make sense to teach an exception to a rule when that exception applies to exactly one function (i.e., main()) and that exception isn't even necessary?
  2. If you ever go back to C programming, especially if you are working in embedded systems where you may not be using the most recent compiler, you will need to forget that exception anyway.

Impressing your interviewer

Why does the following program not compile?

#include <iostream>
#include <cmath>

int main() {
    double value;
    std::cout << "Enter a value: ";
    std::cin >> value;

    std::cout << "W(" << value << ") = " << W(value) << std::endl;
}

double W( double x ) {
    return std::abs( 3.0 - std::abs( 3.0*x ) );
}

When the compiler gets to the line with W(value), it needs to know what is being printed: is it an int, an unsigned int, a double or an instance of a completely different class. With neither a function declaration, and with the function definition not yet reached, the compiler is simply unaware of what to do at this point.

A compiler for a different programming language may make multiple passes through the code: first to find all functions that are defined, and only then to make a second pass where it processes the balance of the code. C++ does not do this: it must be aware of the properties of all functions, classes, etc. before they are ever called. If W(...) was either declared at the top of this function, or the function definition was moved to in front of main(), then the compiler would be immediately aware that it should be calling the appropriate function to print a double.

Question: Did you get this far, and if so, did this help or not, and if you still think our approach is bad, please let Douglas know.

Acknowledgements: J.B.