The Artima Developer Community
Sponsored Link

Python Buzz Forum
Koenig's first rule of debugging

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Thomas Guest

Posts: 236
Nickname: tag
Registered: Nov, 2004

Thomas Guest likes dynamic languages.
Koenig's first rule of debugging Posted: Aug 23, 2007 4:50 PM
Reply to this message Reply

This post originated from an RSS feed registered with Python Buzz by Thomas Guest.
Original Post: Koenig's first rule of debugging
Feed Title: Word Aligned: Category Python
Feed URL: http://feeds.feedburner.com/WordAlignedCategoryPython
Feed Description: Dynamic languages in general. Python in particular. The adventures of a space sensitive programmer.
Latest Python Buzz Posts
Latest Python Buzz Posts by Thomas Guest
Latest Posts From Word Aligned: Category Python

Advertisement

In his C++ blog over at DDJ Andrew Koenig presents his first rule of debugging, which is to make sure the program you’re trying to debug is the program you’re actually running. He explains:

For example, before you ran your program, did you compile it? Are you sure? Are you sure that you compiled every piece of source code that you’re using? With the same compiler? Are you sure that you saved the code before you compiled it.

I’ve lost track of how many times I’ve had a program crash on me, then removed all object and executable files, then recompiled everything from scratch, and had it work perfectly.

Notice that Koenig doesn’t suggest you save all changes and rebuild before running: a decent IDE makes it hard to work in any other way. No, if you want to be safe go in and remove all object and executable files – actually, remove all derived files, since maybe your build generates intermediate files other than just objects and executables.

This suggests to me that there’s something wrong with the build itself. Dependencies aren’t working properly. I’ve certainly lost count of the times that happens. Isn’t the Rebuild All button on Visual Studio unnecessary? Shouldn’t a simple Build always get the job done? How many times has make clean failed to clean up? Just how long will it take to rebuild all that heavily templated C++ code?

C++ programmers, share your pain!

If a C++ expert like Andrew Koenig has trouble with build dependencies, what hope for the rest of us?

Makefiles are a proven and stable technology which, at heart, are based on a simple idea. I’ve been using them for a long time. I still can’t get them right, and judging by the number of variant build systems, I’m not the only one. What’s worse, in a multi-platform environment, you’ll need to tweak them for each platform, maintain them in parallel with project files and solutions. I’ve known people who can get this right, but it takes considerable effort. Most programmers, like me, want to write and run code, and to minimise the distance between the two activities. I don’t like sorting out the build.

Suppose the problem you’re debugging manifests itself in a release build – according to Koenig’s rule, it’s the release build you must debug. Release builds, though, aren’t very tractable. Assertions are gone, memory access checks suppressed, debugging symbols absent. I’ve pointed out the madness of developing two versions of the code before. It’s all too common to use one build for development and then ship something completely different.

In Overload 80, Roger Orr confronts this problem in his fine article “Release Mode Debugging”. He states his preference for a single build and goes on to provide specific advice on compiler options to achieve a build which suits both developers and customers. He also notes that only a small percentage of any code base is performance critical, and only compiler optimisations should be selectively applied to these hot spots. I agree with most of what Orr says but I’m not sure about adding this subtle mix of compiler options to the build system: my preference is to code everything in a high-level language like Python, then rewrite the hot spots in C++, optimised as necessary.

On the subject of rules and laws, have a look at Proebsting’s Law, which asserts:

… while hardware computing horsepower increases at roughly 60%/year, compiler optimizations contribute only 4%.

I can honestly say I’ve never once needed to apply Koenig’s first rule of program debugging when working with Python, or any other high level language. It just isn’t an issue.

C is a great language for certain domains but its compile and build model is a weak spot. C++ surpasses C for most things but its compile and build model is worse.

A problem on line 106
/usr/include/c++/4.0.0/bits/stl_algo.h: In function '_OutputIterator
std::set_union(_InputIterator1, _InputIterator1, _InputIterator2,
_InputIterator2, _OutputIterator) [with _InputIterator1 =
std::_Rb_tree_const_iterator<ip_address>, _InputIterator2 =
__gnu_cxx::__normal_iterator<ip_address*, std::vector<ip_address,
std::allocator<ip_address> > >, _OutputIterator = std::vector<ip_address,
std::allocator<ip_address> >]': ip_sets.cpp:106: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algo.h:4107: error: no match for 'operator*' in
'*__result' ip_sets.cpp:106: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algo.h:4112: error: no match for 'operator*' in
'*__result' ip_sets.cpp:106: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algo.h:4117: error: no match for 'operator*' in
'*__result' /usr/include/c++/4.0.0/bits/stl_algo.h:4121: error: no match for
'operator++' in '++__result'
/usr/include/c++/4.0.0/bits/stl_iterator_base_types.h: At global scope:
/usr/include/c++/4.0.0/bits/stl_iterator_base_types.h: In instantiation of
'std::iterator_traits<std::vector<ip_address, std::allocator<ip_address> > >':
/usr/include/c++/4.0.0/bits/stl_algobase.h:310: instantiated from '_OI
std::__copy_aux(_II, _II, _OI) [with _II =
std::_Rb_tree_const_iterator<ip_address>, _OI = std::vector<ip_address,
std::allocator<ip_address> >]' /usr/include/c++/4.0.0/bits/stl_algobase.h:326:
instantiated from 'static _OI std::__copy_normal<<anonymous>, <anonymous>
>::copy_n(_II, _II, _OI) [with _II = std::_Rb_tree_const_iterator<ip_address>,
_OI = std::vector<ip_address, std::allocator<ip_address> >, bool <anonymous> =
false, bool <anonymous> = false]'
/usr/include/c++/4.0.0/bits/stl_algobase.h:387: instantiated from
'_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator)
[with _InputIterator = std::_Rb_tree_const_iterator<ip_address>, _OutputIterator
= std::vector<ip_address, std::allocator<ip_address> >]'
/usr/include/c++/4.0.0/bits/stl_algo.h:4124: instantiated from '_OutputIterator
std::set_union(_InputIterator1, _InputIterator1, _InputIterator2,
_InputIterator2, _OutputIterator) [with _InputIterator1 =
std::_Rb_tree_const_iterator<ip_address>, _InputIterator2 =
__gnu_cxx::__normal_iterator<ip_address*, std::vector<ip_address,
std::allocator<ip_address> > >, _OutputIterator = std::vector<ip_address,
std::allocator<ip_address> >]' ip_sets.cpp:106: instantiated from here
/usr/include/c++/4.0.0/bits/stl_iterator_base_types.h:129: error: no type named
'iterator_category' in 'class std::vector<ip_address, std::allocator<ip_address>
>' /usr/include/c++/4.0.0/bits/stl_algobase.h: In static member function 'static
_OI std::__copy<<anonymous>, <template-parameter-1-2> >::copy(_II, _II, _OI)
[with _II = std::_Rb_tree_const_iterator<ip_address>, _OI =
std::vector<ip_address, std::allocator<ip_address> >, bool <anonymous> = false,
<template-parameter-1-2> = std::bidirectional_iterator_tag]':
/usr/include/c++/4.0.0/bits/stl_algobase.h:317: instantiated from '_OI
std::__copy_aux(_II, _II, _OI) [with _II =
std::_Rb_tree_const_iterator<ip_address>, _OI = std::vector<ip_address,
std::allocator<ip_address> >]' /usr/include/c++/4.0.0/bits/stl_algobase.h:326:
instantiated from 'static _OI std::__copy_normal<<anonymous>, <anonymous>
>::copy_n(_II, _II, _OI) [with _II = std::_Rb_tree_const_iterator<ip_address>,
_OI = std::vector<ip_address, std::allocator<ip_address> >, bool <anonymous> =
false, bool <anonymous> = false]'
/usr/include/c++/4.0.0/bits/stl_algobase.h:387: instantiated from
'_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator)
[with _InputIterator = std::_Rb_tree_const_iterator<ip_address>, _OutputIterator
= std::vector<ip_address, std::allocator<ip_address> >]'
/usr/include/c++/4.0.0/bits/stl_algo.h:4124: instantiated from '_OutputIterator
std::set_union(_InputIterator1, _InputIterator1, _InputIterator2,
_InputIterator2, _OutputIterator) [with _InputIterator1 =
std::_Rb_tree_const_iterator<ip_address>, _InputIterator2 =
__gnu_cxx::__normal_iterator<ip_address*, std::vector<ip_address,
std::allocator<ip_address> > >, _OutputIterator = std::vector<ip_address,
std::allocator<ip_address> >]' ip_sets.cpp:106: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algobase.h:269: error: no match for 'operator++'
in '++__result' /usr/include/c++/4.0.0/bits/stl_algobase.h:270: error: no match
for 'operator*' in '*__result' /usr/include/c++/4.0.0/bits/stl_algobase.h: In
static member function 'static _OI std::__copy<_BoolType,
std::random_access_iterator_tag>::copy(_II, _II, _OI) [with _II = ip_address*,
_OI = std::vector<ip_address, std::allocator<ip_address> >, bool _BoolType =
false]': /usr/include/c++/4.0.0/bits/stl_algobase.h:317: instantiated from '_OI
std::__copy_aux(_II, _II, _OI) [with _II = ip_address*, _OI =
std::vector<ip_address, std::allocator<ip_address> >]'
/usr/include/c++/4.0.0/bits/stl_algobase.h:335: instantiated from 'static _OI
std::__copy_normal<true, false>::copy_n(_II, _II, _OI) [with _II =
__gnu_cxx::__normal_iterator<ip_address*, std::vector<ip_address,
std::allocator<ip_address> > >, _OI = std::vector<ip_address,
std::allocator<ip_address> >]' /usr/include/c++/4.0.0/bits/stl_algobase.h:387:
instantiated from '_OutputIterator std::copy(_InputIterator, _InputIterator,
_OutputIterator) [with _InputIterator =
__gnu_cxx::__normal_iterator<ip_address*, std::vector<ip_address,
std::allocator<ip_address> > >, _OutputIterator = std::vector<ip_address,
std::allocator<ip_address> >]' /usr/include/c++/4.0.0/bits/stl_algo.h:4124:
instantiated from '_OutputIterator std::set_union(_InputIterator1,
_InputIterator1, _InputIterator2, _InputIterator2, _OutputIterator) [with
_InputIterator1 = std::_Rb_tree_const_iterator<ip_address>, _InputIterator2 =
__gnu_cxx::__normal_iterator<ip_address*, std::vector<ip_address,
std::allocator<ip_address> > >, _OutputIterator = std::vector<ip_address,
std::allocator<ip_address> >]' ip_sets.cpp:106: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algobase.h:285: error: no match for 'operator*'
in '*__result' /usr/include/c++/4.0.0/bits/stl_algobase.h:287: error: no match
for 'operator++' in '++__result'

Read: Koenig's first rule of debugging

Topic: Doctest for Ruby Previous Topic   Next Topic Topic: The Shrinking Python Web Framework World

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use