Thursday, July 26, 2007

Why Continuous Syntax Checking Matters

Today, I ran into a great example of why continuous syntax checking matters. Now, I understand that some of the slowness that I experienced in diagnosing this problem is because I'm still getting used to C++ and Boost and the resulting error messages. but still...

Here's the relevant chunk of code with the error in bold and line 69 pointed out for future reference.


--> Line 69

boost::program_options::options_description config( "Config File Options ");
config.add_options()
( "currentTime", boost::program_options::value()->default_value(defaultDateString), "YYYY-MM-DD HH:MM:SS" )
( "df", boost::program_options::value(), "description" )
( "debugDir", boost::program_options::value(), "location for log file" )
( "workingDir", boost::program_options::value(), "all intermediate files will go here" )
( "script", boost::program_options::value(), "script directory (location of func)" )
( "DBName", boost::program_options::value<std::string()>(), "name of database" )
( "DBUserName", boost::program_options::value< std::string >(), "username for database" )
( "DBPassword", boost::program_options::value< std::string >(), "password for database" )
( "DBSchema", boost::program_options::value(), "schema to be used for database" )
( "ASchema", boost::program_options::value(), "schema to access A tables" )
( "PSchema", boost::program_options::value(), "schema to access P tables" )
( "opsEmail", boost::program_options::value(), "operations email address" )
( "researchEmail", boost::program_options::value(), "research email address" );




And I'll just add the error message afterwards, for your enjoyment. I won't belabor the point by actually writing anything afterwards. I think it will be pretty clear. If I had had some kind of auto-syntax checking active, then this would have been a lot easier to find. Probably would have saved 5 minutes of staring at the code and 15 minutes of entering a blog to bitch about it. That's a 20 point swing!

/usr/include/boost/program_options/detail/value_semantic.hpp: In member function `void boost::program_options::typed_value::notify(const boost::any&) const [with T = std::string ()(), charT = char]':
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/program_options/detail/value_semantic.hpp:28: error: function return type cannot be function
/usr/include/boost/program_options/detail/value_semantic.hpp:28: error: function return type cannot be function
/usr/include/boost/any.hpp:172: error: function return type cannot be function
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/program_options/detail/value_semantic.hpp:30: error: assignment of read-only location
/usr/include/boost/program_options/detail/value_semantic.hpp:30: error: cannot convert `std::string ()()' to `std::string ()()' in assignment
/usr/include/boost/program_options/detail/value_semantic.hpp: In function `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]':
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/program_options/detail/value_semantic.hpp:81: error: function return type cannot be function
/usr/include/boost/program_options/detail/value_semantic.hpp:81: error: function return type cannot be function
/usr/include/boost/lexical_cast.hpp:185: error: function return type cannot be function
/usr/include/boost/any.hpp: At global scope:
/usr/include/boost/any.hpp: In instantiation of `boost::any::holder':
/usr/include/boost/any.hpp:159: instantiated from `ValueType* boost::any_cast(boost::any*) [with ValueType = std::string ()()]'
/usr/include/boost/any.hpp:167: instantiated from `const ValueType* boost::any_cast(const boost::any*) [with ValueType = std::string ()()]'
/usr/include/boost/program_options/detail/value_semantic.hpp:28: instantiated from `void boost::program_options::typed_value::notify(const boost::any&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/any.hpp:125: error: field `boost::any::holder::held' invalidly declared function type
/usr/include/boost/any.hpp: In function `ValueType* boost::any_cast(boost::any*) [with ValueType = std::string ()()]':
/usr/include/boost/any.hpp:167: instantiated from `const ValueType* boost::any_cast(const boost::any*) [with ValueType = std::string ()()]'
/usr/include/boost/program_options/detail/value_semantic.hpp:28: instantiated from `void boost::program_options::typed_value::notify(const boost::any&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/any.hpp:159: error: cannot convert `std::string (**)()' to `std::string (*)()' in return
/usr/include/boost/lexical_cast.hpp: In function `Target boost::lexical_cast(Source) [with Target = std::string ()(), Source = std::basic_string, std::allocator >]':
/usr/include/boost/program_options/detail/value_semantic.hpp:81: instantiated from `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]'
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/lexical_cast.hpp:185: error: function return type cannot be function
/usr/include/boost/program_options/detail/value_semantic.hpp:81: instantiated from `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]'
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/lexical_cast.hpp:191: error: invalid conversion from `std::string (*)()' to `int'
/usr/include/boost/lexical_cast.hpp:187: warning: address of local variable `result' returned
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits: At global scope:
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits: In instantiation of `std::numeric_limits':
/usr/include/boost/lexical_cast.hpp:131: instantiated from `boost::detail::lexical_stream::lexical_stream() [with Target = std::string ()(), Source = std::basic_string, std::allocator >]'
/usr/include/boost/lexical_cast.hpp:186: instantiated from `Target boost::lexical_cast(Source) [with Target = std::string ()(), Source = std::basic_string, std::allocator >]'
/usr/include/boost/program_options/detail/value_semantic.hpp:81: instantiated from `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]'
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:290: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:292: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:295: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:297: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:299: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:301: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:304: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:308: error: function return type cannot be function
/usr/include/boost/lexical_cast.hpp: In member function `bool boost::detail::lexical_stream::operator>>(InputStreamable&) [with InputStreamable = std::string ()(), Target = std::string ()(), Source = std::basic_string, std::allocator >]':
/usr/include/boost/lexical_cast.hpp:189: instantiated from `Target boost::lexical_cast(Source) [with Target = std::string ()(), Source = std::basic_string, std::allocator >]'
/usr/include/boost/program_options/detail/value_semantic.hpp:81: instantiated from `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]'
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/lexical_cast.hpp:149: error: ambiguous overload for 'operator>>' in '((boost::detail::lexical_stream, std::allocator > >*)this)->boost::detail::lexical_stream, std::allocator > >::stream >> output'
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/bits/istream.tcc:87: note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>&(*)(std::basic_istream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits]
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/bits/istream.tcc:93: note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_ios<_CharT, _Traits>&(*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits]
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/bits/istream.tcc:102: note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::ios_base&(*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits]
make[1]: *** [debug.obj/SVCExecutable.o] Error 1
make[1]: Leaving directory `/data/aykroyd/cvs/Optimization/five0/PredictionAndBidding/SegmentVolumeCalculator'
make: *** [default] Error 2
make: Leaving directory `/data/aykroyd/cvs/Optimization/five0/PredictionAndBidding/SegmentVolumeCalculator'
exit
Connection to master closed.

exit

Compilation exited abnormally with code 2 at Thu Jul 26 10:53:43

Tuesday, July 24, 2007

emacs and the search for tool zen

NOTE: Originally, this was going to be one post with everything that I've figured out so far about how to use emacs, what tools to extend it with, and what custom extensions to hand-roll based on my current needs. Unfortunately, my tendency towards diarrhea of the mouth being what it is, I've filled more space than I feel comfortable spending on drivel about why I care about this, why tools are important, and why my individual needs are like a unique snow flake that everyone should care about. So, in the interests of optimizing the organization of the information a bit, I'm breaking it up. So this post will contain only introductory and motivation of problem-type content. Future posts will cover what I've actually done, ideas that I like, and hopefully provide some value at least based on the combination of ideas, if not the originality.

So I recently moved from Boston to Northern California. Very shortly thereafter, the startup that I had been at for nearly 2 years was acquired and I was on the job market. I've ended up taking a job with the engineering group in a smallish R&D team that works on optimization problems. The environment is completely different and in many ways I feel like I've stepped back about 20 years into the history of programming. We have to do most of our builds, debugging, etc on remote machines across a connection that is too slow for X forwarding, so most of the coding happens remotely as well. Since I've spent 5 years in Java-based IDEs -- first Eclipse and then IntelliJ, writing C++ ssh'd into a server is unfamiliar ground for me. So I decided to figure out what everyone else was using to do their development. And I was stunned to learn that my new colleagues used vim + grep...

and that was it...

vim and grep ...

To be frank, after having just finished my first warm-up coding assignment during which I was reintroduced to compiler errors that results from misspelled variables and calls to functions that don't exist: m_InitDatabase not m_initDatabase or obj->Run() not obj->Start(), I was hoping for a bit more than that.

So that's the fluffy background... I like tools that make it easier, faster, and more enjoyable to cut code. So I'm in search of the "right" development environment to make me productive with this new set of environmental constraints. I suspect it will be a somewhat lengthy process to configure my environment as well as I'd like and this blog will hopefully reflect that as well other topics that I find interesting.

So why bother?

I have the sense that people who use stock VIM and whatever else is available from bash wonder why I care. The power offered by the standard toolset available on any Unix system is amazing and I think it's important for developers to be comfortable using those tools. Spend any amount of time debugging production issues on servers and your knowledge of UNIX will be rewarded. But I've also been pampered by the amazing development tools offered by IntelliJ and developing without such tools feels needlessly painful. So I'll throw out a random laundry list of things that I love about IntelliJ (not that most of them are exclusive to it. But they are well executed there):
  1. Auto Completion: First, you don't make spelling mistakes and the completion list is a crutch to jog your memory of just what you named a variable or method anyway. Second, it serves as an inline method of looking at simple documentation. Often you can avoid a trip to google to search for an API's documentation just by checking completion options on an object. Both of these uses save a lot of tme.
  2. Fast Keyboard-based File Access: IntelliJ has this feature that I'm in love with. I think more than anything, this is what won me over to it coming from Eclipse. If you press Command-n, and start typing a class name "mysimpl" it will generate a list of all the classes in the project that match that search string. If there are none it will search in your library. Alone, that's pretty cool. But it also has a number of shortcuts. For example, if you type only capital letters, it will let any lower case letter be in between them (e.g., MSS matches MySimpleServer or ManualSarcasmService). This same tool can also be used to search files (excluding java files) and for symbols.
  3. Code Generation: One of the things that I love about really expressive languages is how succinctly you can express yourself. But most of day to day use Java or C++ and with these languages there is a lot of boiler plate code: from class definitions to constructors, getters/setters, to equals and hashcode methods. After using IntelliJ for a while it stopped occurring to me that I should ever have to write these methods unless there was something out of the ordinary. Writing boiler plate code by hand is error-prone and a waste of time. What I like about IntelliJ's execution of this versus Visual Studio was that it's not wizard-based. I define a class member in the .java file and then position the cursor where I want the getter/setter to go, hit Ctrl-n, select getter/setter, and I'm done. No wizards, no mouse clicks, no graphic representations of my class... done.
  4. Finding Uses of Methods/Variables: When debugging a problem, learning a new code base, or thinking about a refactor, it's incredibly useful to be able to jump from a method invocation to its implementation or find all of the uses of a method. Similarly, IntelliJ provides tools to see a graphic representation of an object's hierarchy. By contrast, determining where the method or class is implemented, opening that file, and then moving to the definition is just too slow.
  5. Source Control Integration: I don't mind using svn or cvs command lines for some operations. But generally when I want to diff a file with a previous version or look at its history, I'm actually looking at the file in my editor. So it's handy (I might start to belabor the point... time saving) to perform that operation in the context of my editor.
  6. Integrated Debugging: I'll admit it. I'm a wus. I don't like using command line debuggers. Everything about typing list to see where I am in the file and setting breakpoints by file and line number feels wrong to me. I understand that this is because I'm lacking character. And I'm not hardcore. But I'm not going to change. I like having the option of using a mouse when I debug.
So there's a few of the high impact features that I've come to expect from my development environment. Without these, I find coding and code related activities to be markedly slower and I find myself doing work that would be better completed by a computer. Computers are way more patient than I am.

In the posts that I'll be adding soon I'm going to talk about emacs22, tramp, and a number of extensions that I've been testing.