Why people don't read error messages, and Clang

I find it interesting that new programmers often don't read/understand error messages. I didn't when I was starting, and I just saw a thread where the error message was "class ... does not have member... " and someone had to point out to them that "no, the class does not have that member."

I think the big problem is that there's so much useless information surrounding the actual message, and the message uses cryptic terms.

Although I have gotten used to it by now, I also recently started using clang for a few projects, and it's quite a bit nicer. When I forget a semicolon as here:

        static unsigned int i = 0;
        ostringstream toDisplay
                                 
        toDisplay << getVolume() << " | ";
        XStoreName(dpy, DefaultRootWindow(dpy), toDisplay.str().c_str());

Instead of this with gcc:

sdwmstatus.cpp: In function ‘int main(int, char**)’:
sdwmstatus.cpp:214:9: error: expected initializer before ‘toDisplay’
sdwmstatus.cpp:225:49: error: ‘toDisplay’ was not declared in this scope

I get this with clang:

sdwmstatus.cpp:212:32: error: expected ';' at end of declaration
        ostringstream toDisplay
                               ^
                               ;
1 error generated.

with "error" red, the caret light green, and the missing semicolon dark green.

Not only is this more friendly to the new programmer, it's also more friendly to the seasoned guru who, even though she immediately recognizes that it's a missing semicolon error despite the message not saying so, still has to go to line 214 and look up and also read the next message and figure out it was caused by the first, rather than being shown exactly where the error is.

Here's another example. I used a nonexistant constructor for a string:

sdwmstatus.cpp: In function ‘int main(int, char**)’:
sdwmstatus.cpp:210:23: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
In file included from /usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/string:55:0,
                 from /usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/locale_classes.h:42,
                 from /usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/ios_base.h:43,
                 from /usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/ios:43,
                 from /usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/ostream:40,
                 from /usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/iostream:40,
                 from sdwmstatus.cpp:5:
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.tcc:214:5: error:   initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]

clang:

csdwmstatus.cpp:210:12: error: no matching constructor for initialization of 'string' (aka 'basic_string<char>')
    string thestring(5);
           ^         ~
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:444:7: note: candidate constructor not
      viable: no known conversion from 'int' to 'const std::allocator<char>' for 1st argument
      basic_string(const _Alloc& __a);
      ^
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:451:7: note: candidate constructor not
      viable: no known conversion from 'int' to 'const std::basic_string<char>' for 1st argument
      basic_string(const basic_string& __str);
      ^
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:486:7: note: candidate constructor not
      viable: no known conversion from 'int' to 'const char *' for 1st argument
      basic_string(const _CharT* __s, const _Alloc& __a = _Alloc());
      ^
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:528:9: note: candidate constructor
      template not viable: requires at least 2 arguments, but 1 was provided
        basic_string(_InputIterator __beg, _InputIterator __end,
        ^
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:433:7: note: candidate constructor not
      viable: requires 0 arguments, but 1 was provided
      basic_string()
      ^
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:458:7: note: candidate constructor not
      viable: requires at least 2 arguments, but 1 was provided
      basic_string(const basic_string& __str, size_type __pos,
      ^
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:467:7: note: candidate constructor not
      viable: requires 4 arguments, but 1 was provided
      basic_string(const basic_string& __str, size_type __pos,
      ^
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:479:7: note: candidate constructor not
      viable: requires at least 2 arguments, but 1 was provided
      basic_string(const _CharT* __s, size_type __n,
      ^
/usr/lib/gcc/i686-pc-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/basic_string.h:493:7: note: candidate constructor not
      viable: requires at least 2 arguments, but 1 was provided
      basic_string(size_type __n, _CharT __c, const _Alloc& __a = _Alloc());
      ^
1 error generated.

Here, the clang message is much longer but actually identifies the error and suggests possible fixes and explains why it had to give an error.

It's also really nice that it indents the wraps when your terminal isn't big enough to display the whole thing.

Has anyone else tried out clang or have ideas about those pesky error messages, ie the only part of the compiler we really interact with?

WizenedEE:
I find it interesting that new programmers often don't read/understand error messages. I didn't when I was starting, and I just saw a thread where the error message was "class ... does not have member... " and someone had to point out to them that "no, the class does not have that member."

I think the big problem is that there's so much useless information surrounding the actual message, and the message uses cryptic terms.

Although I have gotten used to it by now, I also recently started using clang for a few projects, and it's quite a bit nicer. When I forget a semicolon as here:

        static unsigned int i = 0;

ostringstream toDisplay
                               
       toDisplay << getVolume() << " | ";
       XStoreName(dpy, DefaultRootWindow(dpy), toDisplay.str().c_str());



Instead of this with gcc:


sdwmstatus.cpp: In function ‘int main(int, char**)’:
sdwmstatus.cpp:214:9: error: expected initializer before ‘toDisplay’
sdwmstatus.cpp:225:49: error: ‘toDisplay’ was not declared in this scope




I get this with clang:


sdwmstatus.cpp:212:32: error: expected ';' at end of declaration
       ostringstream toDisplay
                              ^
                              ;
1 error generated.



with "error" red, the caret light green, and the missing semicolon dark green.

Not only is this more friendly to the new programmer, it's also more friendly to the seasoned guru who, even though she immediately recognizes that it's a missing semicolon error despite the message not saying so, still has to go to line 214 and look up and also read the next message and figure out it was caused by the first, rather than being shown exactly where the error is.

The current development version of GCC 4.8 has such messages. It hasn't been released yet, but it will be released in a bit. But until the Arduino developers decide to ship it, instead of a compiler that is 4 major releases out of date and was released on August 27, 2008, you won't see it as a user.

I find it interesting that new programmers often don't read/understand error messages.

No kidding. I worked helpdesk in the computer center while an undergrad, and you wouldn't believe how many times I had these conversations:

#1:
User: My program keeps giving me a divide by zero error. What does that mean?
me: you're dividing by zero.
User: Oh.

#2:

User: My program keeps giving me a divide by zero error. Why?
me: you're dividing by zero.
User: no I'm not, I'm dividing by N.
me: Well, the value of N is zero.
User: Oh.