strategy for .h files?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

strategy for .h files?

Rik-4
5/1/17

jwe,

Can we define a strategy for the .h files so there is a goal for what we
want them to do?

In most projects I have seen there is a convention that if there is a
header file XXX.h it is associated with a C++ file XXX.cc.  For starters,
we have lots of instances where this is not true which I find confusing.  I
filed an issue report about that here
(https://savannah.gnu.org/bugs/index.php?50906).

Second, the header file itself can be accomplishing two things.  It can
contain the prototypes and API for XXX.cc.  In this case it is generally
included by OTHER header or C++ files, in addition to XXX.cc.  For this
usage case the header file should be as lightweight as possible since the
pre-processor is going to have to grab and process it multiple times.  The
second case I have seen is that the header file is more about consolidating
and making the code in XXX.cc more readable.  If XXX.cc is using header
files from the C stdlib, C++ stdlib, liboctave, libinterp, and local
includes then there might be as much as a page worth of #includes.  Instead
of having all of that boilerplate in XXX.cc it is abstracted to XXX.h.  And
then XXX.cc has a really minimal include list of "#include "XXX.h".

Both strategies are good, and you can even mix them if you want to do some
grepping and determine which header files are used multiple times
(API-style header file) versus just once (consolidation header).

Any thoughts about what strategy Octave should use?

--Rik

Reply | Threaded
Open this post in threaded view
|

Re: strategy for .h files?

John W. Eaton
Administrator
On 05/01/2017 12:38 PM, Rik wrote:

> 5/1/17
>
> jwe,
>
> Can we define a strategy for the .h files so there is a goal for what we
> want them to do?
>
> In most projects I have seen there is a convention that if there is a
> header file XXX.h it is associated with a C++ file XXX.cc.  For starters,
> we have lots of instances where this is not true which I find confusing.  I
> filed an issue report about that here
> (https://savannah.gnu.org/bugs/index.php?50906).

I commented there, but I'll repeat here:

For the files like CColVector.cc, the corresponding header files are
included because of mx-base.h.

oct-norm.{h,cc} is definitely a weird one...

I assume most of the others eventually include the corresponding .h file
by way of including some other header. But making that explicit
shouldn't hurt.

I'll also add that I think I created mx-base.h because it seemed simpler
than repeating a possibly long list of header files in each of those
source files.

About a year ago, I started trying to convert those files to use
templates more effectively, so maybe we could eliminate the need for
some of those specific classes like ComplexColumnVector and replace them
with templates instead (column_vector<Complex>.  These files also define
a number of mixed-type operations, so maybe there is a better way for
the classes and functions they define to be organized so that the number
of header files can be limited a bit.

> Second, the header file itself can be accomplishing two things.  It can
> contain the prototypes and API for XXX.cc.  In this case it is generally
> included by OTHER header or C++ files, in addition to XXX.cc.  For this
> usage case the header file should be as lightweight as possible since the
> pre-processor is going to have to grab and process it multiple times.  The
> second case I have seen is that the header file is more about consolidating
> and making the code in XXX.cc more readable.  If XXX.cc is using header
> files from the C stdlib, C++ stdlib, liboctave, libinterp, and local
> includes then there might be as much as a page worth of #includes.  Instead
> of having all of that boilerplate in XXX.cc it is abstracted to XXX.h.  And
> then XXX.cc has a really minimal include list of "#include "XXX.h".
>
> Both strategies are good, and you can even mix them if you want to do some
> grepping and determine which header files are used multiple times
> (API-style header file) versus just once (consolidation header).
>
> Any thoughts about what strategy Octave should use?

I agree that cleaning things up would be good.  I'm not sure what is best.

I generally try to keep the standard includes out of our header files,
but sometimes you can't get away with a <iosfwd> or some other simple
forward declaration so they are needed.  The same applies for our own
headers.

jwe


Reply | Threaded
Open this post in threaded view
|

Re: strategy for .h files?

Rik-4
On 05/02/2017 12:17 PM, John W. Eaton wrote:

> On 05/01/2017 12:38 PM, Rik wrote:
>> 5/1/17
>>
>> jwe,
>>
>> Can we define a strategy for the .h files so there is a goal for what we
>> want them to do?
>>
>> In most projects I have seen there is a convention that if there is a
>> header file XXX.h it is associated with a C++ file XXX.cc.  For starters,
>> we have lots of instances where this is not true which I find confusing.  I
>> filed an issue report about that here
>> (https://savannah.gnu.org/bugs/index.php?50906).
>
> I commented there, but I'll repeat here:
>
> For the files like CColVector.cc, the corresponding header files are
> included because of mx-base.h.
>
> oct-norm.{h,cc} is definitely a weird one...
>
> I assume most of the others eventually include the corresponding .h file
> by way of including some other header. But making that explicit shouldn't
> hurt.
>
> I'll also add that I think I created mx-base.h because it seemed simpler
> than repeating a possibly long list of header files in each of those
> source files.
>
> About a year ago, I started trying to convert those files to use
> templates more effectively, so maybe we could eliminate the need for some
> of those specific classes like ComplexColumnVector and replace them with
> templates instead (column_vector<Complex>.  These files also define a
> number of mixed-type operations, so maybe there is a better way for the
> classes and functions they define to be organized so that the number of
> header files can be limited a bit.
>
>> Second, the header file itself can be accomplishing two things.  It can
>> contain the prototypes and API for XXX.cc.  In this case it is generally
>> included by OTHER header or C++ files, in addition to XXX.cc.  For this
>> usage case the header file should be as lightweight as possible since the
>> pre-processor is going to have to grab and process it multiple times.  The
>> second case I have seen is that the header file is more about consolidating
>> and making the code in XXX.cc more readable.  If XXX.cc is using header
>> files from the C stdlib, C++ stdlib, liboctave, libinterp, and local
>> includes then there might be as much as a page worth of #includes.  Instead
>> of having all of that boilerplate in XXX.cc it is abstracted to XXX.h.  And
>> then XXX.cc has a really minimal include list of "#include "XXX.h".
>>
>> Both strategies are good, and you can even mix them if you want to do some
>> grepping and determine which header files are used multiple times
>> (API-style header file) versus just once (consolidation header).
>>
>> Any thoughts about what strategy Octave should use?
>
> I agree that cleaning things up would be good.  I'm not sure what is best.
>
> I generally try to keep the standard includes out of our header files,
> but sometimes you can't get away with a <iosfwd> or some other simple
> forward declaration so they are needed.  The same applies for our own
> headers.
>

jwe,

Summarizing, Octave's aim is for lightweight header files.  These should
include the minimal number of #includes necessary for the header file
itself to compile correctly (And can you add the test you used as a
Makefile target?).  Even when a class is mentioned, consider whether a
simple forward declaration of the class is sufficient rather than including
a complete header file.  As an example of the last point, many headers in
the interpreter library have input or output arguments which are of type
octave_value.  Unless the header file does actual is type converting by
calling "octave_value (xxx)", there is no need to '#include "ov.h"' when
"class octave_value;" will do.

--Rik


Reply | Threaded
Open this post in threaded view
|

Re: strategy for .h files?

John W. Eaton
Administrator
On 05/02/2017 04:18 PM, Rik wrote:

> Summarizing, Octave's aim is for lightweight header files.  These should
> include the minimal number of #includes necessary for the header file
> itself to compile correctly (And can you add the test you used as a
> Makefile target?).

The test I used worked on the installed set of header files.  I'll see
if I can come up with something similar that can work in the build tree.

> Even when a class is mentioned, consider whether a
> simple forward declaration of the class is sufficient rather than including
> a complete header file.  As an example of the last point, many headers in
> the interpreter library have input or output arguments which are of type
> octave_value.  Unless the header file does actual is type converting by
> calling "octave_value (xxx)", there is no need to '#include "ov.h"' when
> "class octave_value;" will do.

Yes, as long as it is just the declaration of return type and there is
no inline code for the function that requires calling an actual
constructor function.

I hesitate to use similar forward declarations for std:: objects since
we don't control how they are declared.  Sometimes using "namespace std
{ class FOO; }" might work, but a C++ implementation could do something
different that would cause this type of forward declaration to fail.

jwe



Reply | Threaded
Open this post in threaded view
|

Re: strategy for .h files?

John W. Eaton
Administrator
In reply to this post by Rik-4
On 05/02/2017 04:18 PM, Rik wrote:

> Summarizing, Octave's aim is for lightweight header files.

Generally, yes.  But I would also add that inline function definitions
are fine, provided that they are relatively small and don't require
pulling in system- or feature-dependent header files.

Without inlining things like forwarding through the rep pointer (all the
"rep->foo ()" calls in octave_value, for example) I think the
performance would really suffer.  In the future we might be able to
avoid using reference counting for some of these core classes (like
octave_value) or rely more heavily on link-time optimization, but until
then, we need function inlining and for that to work we have to provide
many function definitions in the header files.

jwe