Boost logo

Boost :

Subject: Re: [boost] Review of a safer memory management approach for C++?
From: Bartlett, Roscoe A (rabartl_at_[hidden])
Date: 2010-06-05 10:02:47


Noel,

> -----Original Message-----
> From: Belcourt, Kenneth
> Sent: Friday, June 04, 2010 10:10 PM
> To: boost_at_[hidden]
> Cc: Bartlett, Roscoe A
> Subject: Re: Review of a safer memory management approach for C++?
>
> ...
>
> > I will argue below that more C++ programs are better served by using
> > more of #2 object-oriented C++ and to a lesser extent template-based
> > methods in #3 and #4 (except where it is called for in lower-level
> > code).
>
> Someone, I think David, asked for a concrete example. A well known
> example is matrices and, for exposition, the additive schwarz
> algorithm described in Saad's Iterative Methods for Sparse Linear
> Systems, page 401, section 13.3.3, available here:
>
> http://www-users.cs.umn.edu/~saad/PS/all_pdf.zip
>
> The serial implementation of this algorithm basically requires A, x,
> b, and A_inv (the inverse of A) where the upper-case variables (A and
> A_inv) are matrices and lower-case (x, b) are vectors. A naive OO
> design might construct a base class called matrix with a virtual
> invert method to invert a matrix.

[Bartlett, Roscoe A]

This is a bad example that has nothing to do with OO specifically. Mathematically, it is not true that *every* matrix is invertible so you should not add an appyInverse(...) to a general matrix interface (either with runtime or compile-time polymorphism). It breaks even the mathematical definition of a linear operator or matrix. Note that Thyra::LinearOpBase does not have an applyInverse(...) for this reason. If you write a templated algorithm that expects to call appyInverse(...) with a compile-time implicit interface, your code is just as wrong as with the runtime OO implementation (except the templated code takes 10 to 1000 times longer to recompile and relink if it does not segfault the compiler first).
 
> My point here is that it might seem reasonable to a less experienced
> developer to use an OO approach and declare a matrix base class with a
> virtual invert method but I think more seasoned developers would
> immediately recognize that approach as flawed. Invoking the additive
> schwarz algorithm with a sparse representation for the A_inv argument
> is usually wrong and is easily diagnosable at compile time. In this
> case, I think most users would prefer a compile error rather than have
> their program fail right after it starts to run, especially for CSE
> HPC applications that have been sitting in the queue for hours waiting
> to run.

[Bartlett, Roscoe A]

So are you suggesting that everyone template all of their code and use implicit template instantiation? That is simply not possible with current software, compilers, and platforms. I can *prove* this with code, compilers, and platforms that we have right now. I have lots of examples.

How to you respond to the following?

When runtime performance or other issues related to dynamic allocations and classic OO are not a problem, classic OO C++ programs using runtime polymorphism are typically superior to highly templated C++ programs using static polymorphism for the following (indisputable) reasons:

1) Well written OO C++ software builds and (more importantly) rebuilds *much* faster than heavily templated code. This massively speeds up the development cycle. The difference can be orders of magnitude of time savings in recompile/relink times. I have seen cases where carefully using runtime OO can result in recompile/relink cycles take less than 20 seconds where using all template code would take 20 minutes. I am *not* exaggerating here at all.

2) Current compilers may not even be able to compile large amounts of template code at all. There are compilers that we have to support (e.g. Sun and IBM) that will segfault or return "internal compiler error" when you give them too much template code. These same compilers have no problem with virtual functions with standard OO. This is reality.

3) Templated programs can result in massive object-code bloat over equivalent runtime OO programs. If you are really sloppy with templates and use it for everything, you can easily double, triple, or more (10x) the size of the object code and executables (see Item 44 in "Effective C++, 3ed edition").

4) The error messages you get when mistakes are made when using explicit interfaces and virtual functions are far superior to the mess that most compliers put out when you make a mistake with implicit compile-time template interfaces. This is a huge issue. Runtime errors, as opposed to cryptic compile-time errors, can be handled by throwing exceptions with very good error messages that programmers can 100% control the quality of. Yes, of course you prefer compile-time errors to runtime errors all things being equal, and am not arguing to prefer runtime errors over compile-time errors in general. This is generally not true of template programming (there are some tricks you can use to improve compile-time error messages, but not perfectly). For example, if you make a mistake with STL iterators/algorithms you can get very cryptic error messages that dumfound most (non-expert and expert) C++ programmers.

5) Well written OO C++ software allows for significant runtime flexibility. If you use dynamic libraries, for instance, you can add new implementations of objects without even having to relink customer executables. Also, you can fix many types of bugs in updated shared libraries without having to recompile/relink customer executables. In a large-scale software setting, this can be very helpful.

********************************************************************************************
*** You can't portably compile and link large C++ programs that template everything!!!!! ***
********************************************************************************************

As long as people keep suggesting that we template all of our codes for every little reason, I am going to keep reminding people of the realities of template code in C++. If you can't respond to the above points (especially #1 and #2) then there is little point in continuing the discussion. Thinking that we are going to drop runtime polymorphism and use exclusively compile-time polymorphism for everything is just fantasy land.

- Ross


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk