Lesson 15: Semantic errors

At this point, we have described syntax errors, code that simply will not compile. There is another type of problem: what happens if your program compiles and executes, but does not do what you wanted it to do? The computer is doing exactly what you programmed, but what you programmed was wrong.

At this point, we have described syntax errors and static semantic errors. In each case, the compiler flags an error where

• a syntax error is when the source code does not match the grammar of the C++ lanugage (two binary operators juxtaposed), and
• a static semantic error is when a requirement of the programming language is not satisfied (invalid types).

There is another type of semantic error: when the programmer incorrectly uses the programming language to solve the problem.

Needs to be fixed.

For example, suppose you wrote a fast cosine functions using a Taylor series, but in copying the numbers you made a mistake: you forgot to include the e-1 on the last number 5.0e-1, making it $5$ instead of $0.5$:

double fast_cosine( double x ) {
return ((
(2.4801587301587302e-5*x*x - 1.3888888888888889e-3)*x*x
+ 4.1666666666666667e-2
)*x*x - 5.0)*x*x + 1.0;
}


Instead of a mistake, you could accidentally have calculated the Taylor series for the cosine function using degrees, rather than radians:

// Return cos(x) where x is in radians
double fast_cosine( double x ) {
return ((
(2.1354943035949858e-19*x*x - 3.9258319857430946e-14)*x*x
+ 3.8663238515629934e-9
)*x*x - 1.5230870989335430e-4)*x*x + 1.0;
}


In this case, the documentation would not actually describe what is actually happening.

Suppose you tried writing an absolute value function, and you got the sign wrong:

// Calculate |x| for a double
double abs( double x ) {
if ( x < 0 ) {
return x;
} else {
return -x;
}
}


Again, it would compile, but it would always return $-|x|$.

A syntax error is the programmer's fault due to a lack of knowledge of the C++ programming language grammar. A semantic error is the programmer's fault

	std::cout << "Hello world!" < std::endl std::cout << "Good night!" < std::endl;


and the compiler will not know what to do when you have a std::endl object juxtaposed to a std::cout statement. In spoken English, either a pause usually indicates the end of a sentence, but the listener can also infer when a sentence ends. The compiler will not guess when you meant to end a sentence.

For example, suppose you say "Let's go to dinner. After lunch, give me a call." If the speaker does not leave a pause between "dinner" and "after", the listener may initially believe that the preposition "after" is meant to start an prepositional phrase meant to modify the verb "go"; however, the listener soon realizes that the statement "Let's go to dinner after lunch" makes no real sense, so the listener is able to switch context and realize that the sentence ended after "dinner" and "After lunch" is the start of a new sentence.

Similarly, every string opens with a ", and closes with one, but if you forget the first, the compiler will not try to interpret the next few characters as a string literal, but as something else. For example, in the following line, all the characters in red are considered the literal string, and then the compiler gets confused when it sees a string juxtaposed with the characters Good:

	std::cout << "Hello world! << std::endl;
std::cout << "Good night! << std::endl;


Humans can forgive such errors; for example, it is an idiotic manner of speech for people to say "quote unquote" preceding a quote. Far too often, someone will actually say "Einstein said quote unquote Imagination is more important than knowledge, and I believe that to be true." The speaker should have said "Einstein said, quote, Imagination is more important than knowledge, unquote, and I believe that to be true." A human can likely determine where the quote ends; however, the compiler will not.

As another example, suppose you entered:

	std::cout << "Hello world!" < std::endl;


The << operator means one thing in C++, while the < operator means something else. Suppose an English speaker were to say "Please calculate 3 eks 4". The listener can guess that "x" looks like a multiplication symbol, and therefore the speaker is attempting to say "Please calculate 3 multiplied by 4." The compiler, however, will not attempt to second guess you. In the above example, the less-than operator does not make any sense between a string and a std::endl.

Similarly, if you incorrectly identify the end-of-line object:

	std::cout << "Hello world!" << std::end;


the compiler cannot and will not guess that you really meant std::endl. For if a listener heard "What affect did that have on the discussion?", the listener could guess that the speaker made a mistake and meant "what effect did that have on the discussion?" The compiler, however, will not try to guess what you meant.

Consequently, unlike spoken English where if the speaker make a mistake, the listener can correct for your mistakes, the compiler will not try to correct your mistake. Instead, it will try to tell you what it doesn't understand.

Like English grammar, the C++ programming language also has a grammar. When you make an error in English where you are using incorrect grammar, that is said to be an error in your syntax. The listener may either attempt to reinterpret your sentence in such a way that it makes sense in the current context, or ask for clarification. The compiler, however, will simply tell you that you have a syntax error.

Definition: grammar
A logical description of what sequences of characters constitute a valid program in a given programming language; consequently, all other sequences of characters do not define a valid program within the language.

Definition: syntax error
An unexpected sequence of characters that is not comprehensible within the grammar of a programming language.

The compiler, however, does try to give you a hint as to what is wrong. Suppose we take the Hello world! program and introduce syntactical errors:

  1   #include <iostream>
2
3   int main();
4
5   int main() {
6   	std::cout << "Hello world!" << std::endl;
7   	std::cout << "Good night!" << std::endl;
8
9   	return 0;
10   }


Let us make the first syntax error: forgetting the semicolon after the first statement with std::cout. If you try to run this, under the compilation tab, you see the message:

 In function 'int main()':
5:5: error: expected ';' before 'std'


First, the error message says where it things the error is: in the function int main(). Next, it gives two numbers: 5:5: The first number is the line number, and the second number is the column. At this point, the compiler is indicating that there probably should have been a semicolon there:

  4   	std::cout << "Hello world!" << std::endl
5   	;std::cout << "Good night!" << std::endl;


Now, we could put the semicolon there, but it looks "nicer" if the semicolon appeared at the end of the previous line.

Second, if you forget to close the first string with a quote, you get the error message:

4:18: warning: missing terminating " character
4:5: error: missing terminating " character


Again, it indicates the line where the problem occurs. First it issues a warning (a string cannot span multiple lines). Then it gets confused and issues an error.

Next, let us make the error where we replace one of the << operators with the < operator. The error message is now bewildering:

 In function 'int main()':
4:33: error: no match for 'operator<' (operand types are 'std::basic_ostream<char>' and '<unresolved overloaded function type>')
4:33: note: candidates are:
In file included from /usr/include/c++/4.9/string:52:0,
from /usr/include/c++/4.9/bits/locale_classes.h:40,
from /usr/include/c++/4.9/bits/ios_base.h:41,
from /usr/include/c++/4.9/ios:42,
from /usr/include/c++/4.9/ostream:38,
from /usr/include/c++/4.9/iostream:39,
from 1:
/usr/include/c++/4.9/bits/basic_string.h:2612:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const _CharT*, const std::basic_string<_CharT, _Traits, _Alloc>&)
operator<(const _CharT* __lhs,
^

/usr/include/c++/4.9/bits/basic_string.h:2612:5: note: template argument deduction/substitution failed:
4:40: note: mismatched types 'const _CharT*' and 'std::basic_ostream<char>'
In file included from /usr/include/c++/4.9/string:52:0,
from /usr/include/c++/4.9/bits/locale_classes.h:40,
from /usr/include/c++/4.9/bits/ios_base.h:41,
from /usr/include/c++/4.9/ios:42,
from /usr/include/c++/4.9/ostream:38,
from /usr/include/c++/4.9/iostream:39,
from 1:
/usr/include/c++/4.9/bits/basic_string.h:2600:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::basic_string<_CharT, _Traits, _Alloc>&, const _CharT*)
operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
^
/usr/include/c++/4.9/bits/basic_string.h:2600:5: note: template argument deduction/substitution failed:
4:40: note: 'std::basic_ostream<char>' is not derived from 'const std::basic_string<_CharT, _Traits, _Alloc>'
In file included from /usr/include/c++/4.9/string:52:0,
from /usr/include/c++/4.9/bits/locale_classes.h:40,
from /usr/include/c++/4.9/bits/ios_base.h:41,
from /usr/include/c++/4.9/ios:42,
from /usr/include/c++/4.9/ostream:38,
from /usr/include/c++/4.9/iostream:39,
from 1:
/usr/include/c++/4.9/bits/basic_string.h:2588:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::basic_string<_CharT, _Traits, _Alloc>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
^
/usr/include/c++/4.9/bits/basic_string.h:2588:5: note: template argument deduction/substitution failed:
4:40: note: 'std::basic_ostream<char>' is not derived from 'const std::basic_string<_CharT, _Traits, _Alloc>'
In file included from /usr/include/c++/4.9/bits/stl_algobase.h:67:0,
from /usr/include/c++/4.9/bits/char_traits.h:39,
from /usr/include/c++/4.9/ios:40,
from /usr/include/c++/4.9/ostream:38,
from /usr/include/c++/4.9/iostream:39,
from 1:
+ almost 100 more lines of error messages...


From the verbosity of this error message, you may think that you suddenly committed a cardinal sin; however, what the compiler is doing is trying to tell you why it is confused and when you have a better understanding of C++, you know it is trying to help you by giving suggestions. The most important line for you, however, is the first:

 In function 'int main()':
4:33: error: no match for 'operator<' ...

This says that on line 4 at column 33, the compiler does not know what to do with the < operator.

Unfortunate, if you were to incorrectly spell std::endl and replace it with std::end, the error message is less clear, but reading the first two lines:

 In function 'int main()':
4:33: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and '<unresolved overloaded function type>')
+ almost 100 more lines of error messages...


What this error message says is that it does not understand how it is supposed to have a << operator work with something it doesn't comprehend. It actually describes the std::end as an unresolved overloaded function type. While the error message is not entirely useful, it does point you to approximately where the error is.

Finally, a very common error is to forget the closing brace. If you forget the closing brace }, you get the error message:

 In function 'int main()':
7:13: error: expected '}' at end of input


In this case, it is telling you exactly what is missing, and you can add it.

If it tells you what is wrong, why not fix it?

In at least two examples above (with the missing semicolon and the missing closing brace) the error message told you exactly what was wrong and how to fix it. You may ask, why does the compiler simply not make the corrections and then carry on? The problem is, what it thinks is the right correction to make may not be what you actually meant!

Important suggestion:
As you go forward and learn new aspects of the C++ programming language, it may not be that bad an idea to occasionally make deliberate mistakes so that you can see what the error messages are.

Review

In your own words, describe each of these concepts:

Questions and practice:

1. What error do you get if you misspell return?

2. What happens if you misspell the function name main, say with min?

3. If you misspelled include, you get a cascade of subsequent errors. If there are multiple errors, always try to fix the first error first; this may eliminate subsequent errors.

4. If you write int main(] { instead of using a closing parenthesis, what are the errors? How is the error worded?