Smart C++ class splitter?

  • Thread starter Daniel Pfeiffer
  • Start date
D

Daniel Pfeiffer

Hi,

for a while now I've been looking for a smart C++ class splitter that allows
programming in one file as in Java. This would eliminate the need of
repeating all declarations differently in the definition.

I guess the reason I can't find anything is that traditional make would be
recompiling tons of stuff all the time. But modern alternatives like makepp
would notice that the updated x.hh is the same as before, so there's no
drawback any more. Essentially I want something like:

/********** x.cpp: **********/
#include <string>
using namespace std;
class X
{
static int i = 0; // illegal, some IDEs might barf :-(
public:
inline void f(string s) { ... }
// bla bla
void g(string s) { ... } // not to be inline!
};


This would get split into the following two files for the compiler to see:

/********** x.hh: **********/
#ifndef _X_CPP_
#define _X_CPP_
#line 1 "x.cpp"
#include <string>

class X
{
static int i;
public:
inline void f(std::string s) { ... }

void g(std::string);
};
#endif

/********** x.cc: **********/
#include "x.hh"
#line 2 "x.cpp"
using namespace std;
#line 5
int X::i = 0;
#line 9
void X::g(string s) { ... }


The other reason is probably that with namespaces, nested classes, enums,
typedefs and whatnot, this rewriting is a rather tough one. But that's
because the whole topic is a mess in C++. I guess this causes numerous
compilations attempts, especially for beginners, until you get it right. All
the more reason to do this!

Any solutions or thoughts?

best regards - Daniel
 
R

Robert Fendt

drawback any more. Essentially I want something like:
[Inline definition]
This would get split into the following two files for the compiler to see:

/********** x.hh: **********/
[Class interface]
/********** x.cc: **********/
[Class implementation]

So you essentially want to write a class in inline form and
then auto-refactor it into an interface and implementation. To
be frank, I do not really see the benefit here, since splitting
off the interface is (at least) as much a matter of readability
and maintenance as compilation time.

I see a few problems with your idea:

(1) Control. Patterns like pointer-to-implementation build on
the fact that the programmer can very carefully choose what bits
of information he/she puts into which compilation unit. So
auto-splitting would probably only work for 'simple' cases
anyway.

(2) Maintenance. You would have to maintain the inline version
of the class in a file and put it through yet another
preprocessor (like C++ didn't already have enough of those:
macros, templates, and Qt adds its own preproc as well). This
just adds complexity without apparent benefit (to me at least).

(3) Readability. Separate interface headers serve among
other things the important purpose of showing, well, the
interface of the class at a glance. So, well-made headers are
usually formatted consistently and are also the place where e.g.
doxygen comments are placed. You would have to have those in
your inline version as well, which will then become in the worst
case a rather large junk piece of unreadable spaghetti code (->
point (2)).

That said, of course sometimes a class is developed in a hurry
and cleaned up only afterwards (i.e., refactored into a separate
interface definition, documented etc.). But in this situation
(and also the other way round, i.e. implementing a previously
designed class structure), the biggest help IMHO comes from a
good IDE.

So in my opinion one would benefit much more from work on
improving available refactoring tools (like e.g. in Eclipse
CDT). And V'Studio users could maybe nag MS to actually
implement refactoring facilities for native C++ (i.e.,
non-.NET). Just my $0.02.

Regards,
Robert
 
Ö

Öö Tiib

Any solutions or thoughts?

I think you do not see the reason why it is so. For example: Someone
developing in javascript has 3 files to deal with (.html, .css
and .js). The contents of these 3 files can be merged into one
(.html). However they usually avoid doing it. Why?

How does your tool know what related headers you want to #include
in .hh and what classes you want only to forward declare in .hh and
#include in .cc?

Or if to put it more generic: How does your tool know what you want to
expose in interface and what you want to encapsulate and hide?
 
D

Daniel Pfeiffer

Hi,

I'm replying here to all who took time to answer, since this one is most
comprehensive.

la 04/04/2010 08:16 PM Robert Fendt skribis:
drawback any more. Essentially I want something like:
[Inline definition]
This would get split into the following two files for the compiler to see:

/********** x.hh: **********/
[Class interface]
/********** x.cc: **********/
[Class implementation]

So you essentially want to write a class in inline form and
then auto-refactor it into an interface and implementation. To
be frank, I do not really see the benefit here, since splitting
off the interface is (at least) as much a matter of readability
and maintenance as compilation time.

I see a few problems with your idea:

(1) Control. Patterns like pointer-to-implementation build on
the fact that the programmer can very carefully choose what bits
of information he/she puts into which compilation unit. So
auto-splitting would probably only work for 'simple' cases
anyway.

I'm not trying to force this on anybody. If this were designed right, it
would probably handle the vast majority of use cases correctly. But whenever
you feel more comfortable or need something not possible with my approach, the
two-file (or more) way is still perfectly valid. Also you could gradually
introduce this where you see fit.

I want an easier way only for those who'd like to use it. All languages that
try to improve on C++, like Java, C# or D went for the single file approach.
So many people seem to like that.
(2) Maintenance. You would have to maintain the inline version
of the class in a file and put it through yet another
preprocessor (like C++ didn't already have enough of those:
macros, templates, and Qt adds its own preproc as well). This
just adds complexity without apparent benefit (to me at least).

Assuming the splitter were bug-free, this would just be one more pattern rule
(at least with makepp, where dependencies fall into place automatically). So
there's nothing to worry about.

As for the benefit, it's a matter of taste. See about other languages above.
(3) Readability. Separate interface headers serve among
other things the important purpose of showing, well, the
interface of the class at a glance. So, well-made headers are
usually formatted consistently and are also the place where e.g.
doxygen comments are placed. You would have to have those in
your inline version as well, which will then become in the worst
case a rather large junk piece of unreadable spaghetti code (->
point (2)).

Maybe the mess is just classes that are too big. For me having the (doxygen)
comment with the method, rather than having to jump to it, seems like an
advantage. As for showing just the interface, that is impossible with C++,
where you're always forced to publish the private parts (unless you mask
everything behind a pointer to a hidden class, IMHO an ugly idiom).

Öö Tiib compared this to splitting js, css and html. But those, to me, are
three different classes of information, so it seems right to separate them,
just as I would still separate classes in my unified C++.

He also addressed the tickly point of separating #include statements
correctly. To this I see two solutions:

1. the simplistic one provides some markup (e.g. #ifdef CXXSPLIT_HEADER) to
help the splitter assign lines to one file or the other.

2. the smart way would read the included headers (would need -D and -U options
to get the #ifdefs right). It would learn everything declared therein, to
find what is needed in which generated file. This was implied in my example
where using namespace was elided from the header, and string turned into
std::string. Should still be much faster than all the work the real compiler
needs to do.
So in my opinion one would benefit much more from work on
improving available refactoring tools (like e.g. in Eclipse
CDT). And V'Studio users could maybe nag MS to actually
implement refactoring facilities for native C++ (i.e.,
non-.NET). Just my $0.02.

It's sad that C++ is so complicated that you (almost) need an IDE just to
write it. Gosh, that's only €0,0149 ;-)

regards - Daniel
 
J

Jonathan Lee

I want an easier way only for those who'd like to use it.  All languages that
try to improve on C++, like Java, C# or D went for the single file approach.
So many people seem to like that.

I'm with you on this. Almost everything in my header files could be
mechanically pulled from the corresponding cpp file. If there was
just a preprocessor directive that did what I was going to do anyway,
I would be much happier.

// #include "bigint.hpp"
#import "bigint.cpp"

--Jonathan
 
Ö

Öö Tiib

Hi,

I'm replying here to all who took time to answer, since this one is most
comprehensive.

Without going into further details ... lets assume it is doable tool
and adds value to several from us.

Have you read Daveed Vandevoorde's modules proposal to standard? I do
not know how far it is currently. Usually progress there means getting
less readable. Readable draft:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1778.pdf

Your tool could achieve both his and yours goals by translating code
extended by that proposal into current C++ (with #includes and
__declspec(dllexports) crap ).
It's sad that C++ is so complicated that you (almost) need an IDE just to write it. Gosh, that's only €0,0149 ;-)

I am surprized that you brought up such "IDE is must to have for C++".
I have observed direct opposite. People using basically a text editor
+ command line scripts are decently productive in C++ team. In Java or
C# team a person with same toolset seems totally directionless.
 
D

Daniel Pfeiffer

la 04/07/2010 11:10 AM Öö Tiib skribis:
On Apr 7, 2:25 am, Daniel Pfeiffer <[email protected]> wrote:
Without going into further details ... lets assume it is doable tool
and adds value to several from us.
Have you read Daveed Vandevoorde's modules proposal to standard? I do
not know how far it is currently. Usually progress there means getting
less readable. Readable draft:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1778.pdf

He's providing an exit from the messy heritage of C. His namespace <<
operator overloading is funny though, but I can live with that.
Your tool could achieve both his and yours goals by translating code
extended by that proposal into current C++ (with #includes and
__declspec(dllexports) crap ).

His semantics with really private and selective visibility goes beyond what is
possible today, so I don't see how it could be translated back into current C++.
I am surprized that you brought up such "IDE is must to have for C++".

I answered to just that implication. I myself use only Emacs for quite a
sizeable project ;-)
I have observed direct opposite. People using basically a text editor
+ command line scripts are decently productive in C++ team. In Java or
C# team a person with same toolset seems totally directionless.

Often enough it takes an extra round of compiler errors to get the header and
implementation compatible, though :-( C++ doesn't flow in my veins, Perl does.
 
Ö

Öö Tiib

la 04/07/2010 11:10 AM Öö Tiib skribis:

He's providing an exit from the messy heritage of C.  His namespace <<
operator overloading is funny though, but I can live with that.

Funny, yes, perhaps it might change. What is useful in his proposal is
that there is a way for user to indicate what he wants to export and
what he wants to hide without making .hh files himself.

It is still better idea than other ideas:
1) custom preprocessor things (#ifdef CXXSPLIT_HEADER) are even
funnier.
2) options of different heuristic split patterns on tool may lack
specific splitting strategy that user wants.
3) When tool first merges from .hh .cc, remembers how it was and later
stores back so then how to refactor hiding/showing?
His semantics with really private and selective visibility goes beyond what is
possible today, so I don't see how it could be translated back into current C++.

Yes, full support to his proposal is not possible to achieve only by
preprocessing. Also, tool might be unable or not want to hide
something that is possible (because of additional tricks needed may
distant the result too lot from source). So it can create .hh files
(and #include directives) that hide as lot it is able and #include as
few it is able. At least it should not think itself what user might
want to hide. When there are ambiguities and/or name conflicts when
compiling the result then it is usually a case of hard-to-read code
that review would flush anyway.
 
D

Daniel Pfeiffer

la 04/07/2010 03:35 AM Jonathan Lee skribis:
I'm with you on this. Almost everything in my header files could be
mechanically pulled from the corresponding cpp file. If there was
just a preprocessor directive that did what I was going to do anyway,
I would be much happier.

I've found it: Lzz: The Lazy C++ Programmer's Tool
<http://www.lazycplusplus.com/> gives just about the identical specification I
gave :)

They even thought of the people who must use a build tool that's not as smart
as makepp. There are options to avoid rewriting header files when they would
be unchanged.

So sad I'm in a well established project :-( This makes me want to start on a
new one!

regards -- Daniel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top