here is a question, just out of curiousity:
If you are given a bunch of .c files, is there a way to recognize (by
just looking at them) whether the code in them is written in C or in C+
+?
What would you look for?
Thanks in advance,
class
iostream
istream, ostream, fstream
virtual
template
>> What would you look for?
>
> class
> iostream
> istream, ostream, fstream
> virtual
> template
Then it might still be C++ without any of these things. It could have a function
inside a struct, for example. But such code - essentially "C-style C++" - is
questionable anyway...
Parse it with a C parser and look if it gives errors.
Can you see what compiler is used?
But by just looking at the code, (as other suggested) I would search for
c++ only stuff, like cout, class, templates, etc
Looking for class and template is good obviously. I'm
not sure I'd bother checking virtual because while you
can put it in a struct that's not common and other things
are better quick checks.
But I'd first check all the #includes for any C++ headers.
Any file that has one is C++, and if any of the .h files
are thus C++, apply recursively. As most people put
their #includes near the top of a file, that's quick to check.
Looking for std:: and using will trap most C++ library
uses as well. (I suppose you should allow for whitespace
between std and :: - but does anyone put any there?)
The latter two are a broader brush than looking for
streams. (Most of my C++ source files don't use
streams.)
All of which are *not* reserved words in C, and might therefore be used
as variable names.
--
Richard Herring
But certaily not in the same way as in C++, so, look for the keywords
and see how they are used. OR, simply, "just look at the code" as was
suggested already.
Depends on the input set.
#include <stdio.h> /* C header
#include <iostream.h>
class xyz {
.
.
.
.
virtual xyzfun...
.
.
public:
.
.
.
private:
protected:
.
.
.
};
friend family relatives;
*/
int main()
{
printf("My C++ program \n");
return 0;
}
Now?
I agree with Juha Nieminen. Thats the best.
How will one determain if a given text is English, French or a mix? We
keep looking for key words? No. Make an English read the text.
Yes, thank you.
Few weeks ago, I tried to include a C header to a C++ program, but
couldn't because it had a variable named "class" in one of defined
structures.
>> But by just looking at the code, (as other suggested) I would search
>> for c++ only stuff, like cout, class, templates, etc
>
> All of which are *not* reserved words in C, and might therefore be used
> as variable names.
The OP said "looking at" the code. I was not suggesting a raw grep that
triggered a boolean result.
--
Phlip
>> class
>> iostream
>> istream, ostream, fstream
>> virtual
>> template
>
> Looking for class and template is good obviously. I'm
> not sure I'd bother checking virtual because while you
> can put it in a struct that's not common and other things
> are better quick checks.
I seem to recall that in C you cannot use 'virtual' as a keyword, and cannot put
a method inside a struct.
Indeed. But I would make a strong prediction that almost all uses of virtual
are inside a class rather than a struct, and therefore looking for class
will
more readily find C++. Yes, looking for virtual will find more C++, but the
only additional cases you'll find will be virtual inside struct, and as I
predict
there won't be many, I'd use a different heuristic to find more cases.
I'm not going to try it, but I suspect that the overwhelming majority of C++
will be found from
- standard C++ headers
- using
- std::
- class
- template
- inclusion of any user header categorised as C++ using the above, applied
recursively
Anyone who wrote any such code in the last 20 years should have known
better.
Rather the reverse. virtual typically appears in abstract interfaces.
Since those interfaces have no private members, they are often declared
as structs.
struct some_abstract_interface
{
virtual void mandatory_override() =0;
virtual void optional_override() { }
// ...
};
Better than what? Writing perfectly valid C code?
It's unnecessary to make the header code incompatible with C++ on such a obvious
issue.
It's like when designing a door to your house: even if you and your wife are
both short people (short people, short people! :-)[1]) you design that door so
that other people can just walk in without risking banging their head.
Or, I would, if I were that short and were designing a door.
Cheers & hth.,
- Alf
Notes:
[1] <url: http://www.google.com/search?q=%22short%20people%22>
--
Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
No ads, and there is some C++ stuff! :-) Just going there is good. Linking
to it is even better! Thanks in advance!
>> Anyone who wrote any such code in the last 20 years should have known
>> better.
>
> Better than what? Writing perfectly valid C code?
Whereas C++ was designed for transparent interoperability with C, yes. Remain
aware, on the C side, how not to break that portability.
That I'd regard as poor style (although of course that doesn't mean it
may not often occur). Putting aside that the sole purpose of this is to
save a few keystrokes, and keystrokes are cheap, and that it conflicts
with about the only useful reason to have both struct and class, to allow
struct to be used for basic C-style structs (and another case I note below)
and class when not, there is a more serious reason.
Lets's suppose I have
struct Base
{
// virtual declarations.
};
Now I write some code, in foo.cpp
#include "base.h";
#include "foo.h"
void foo(const Base & base)
{
// ...
}
and in foo.h
void foo(const Base &);
But I need a forward declaration of Base before that (no point including
base.h).
And the natural thing to use is
class Base;
However the last compiler I ran that code (or something similar) through
gave
me a warning that I'd mixed class and struct. And warnings are not good,
it's generally recognised as good style to avoid them.
So now I need to have it published whether Base is actually defined
using struct or class in order to painlessly forward declare it, regardless
of that this conveys no information ... no, thank you, let's stick to class
everwhere (as that is the usual convention for something that's not a
C-style struct, or possibly something never used in an interface, which
ironically ,in view of where this came from, means that private base
classes without virtual may have no problem being structs).
While on this topic there is another problem, which is if Base is actually
a typedef, which doesn't forward declare well (something that could do
with fixing). Currently also defining a base_fwd.h may be the least bad
solution
to that. Of course you could also do that just to specify struct Base, but
that
I think would be the worst idea in this posting.
Better than writing perfectly valid C that you should know is invalid
C++ (anyone who isn't aware of that there is a C++ and it uses class
a lot should know better). It's just professional to recognise that
there are dual purpose compilers, and also that in any but the
most extreme cases there is the possibility of your C code being
reused as C++ one day (or just you may upgrade to a compiler
that decides to warn you about class) because few of us can see
the future clearly enough to be certain otherwise.
:: should be sufficient to identify C++ source files in many cases, as
it's not valid C (except if in a string/comment/etc.), and will catch uses
of scoped names and definitions of member functions. But some short C++
programs might have "using namespace std;" and thus never use ::.
I got it from Bjarne Stroustrup, in The C++ Programming Language. It's
not poor style. Furthermore, it is very popular, which is the exact
opposite of the main claim from your previous post (which you snipped).
> Putting aside that the sole purpose of this is to
> save a few keystrokes,
"Save" a few keystrokes? That presumes that writing class, followed by
public:, is somehow the natural order of things, and that using struct
deviates from that order. That's ridiculous; if you don't have any
private members, why use a keyword whose sole purpose is to make a
struct's default access level private?
> and keystrokes are cheap, and that it conflicts
> with about the only useful reason to have both struct and class, to allow
> struct to be used for basic C-style structs
That's one possible convention, being your favorite does not make it
"about the only useful reason."
class foo
{
public:
// ...
};
Is more verbose, and IMO no clearer, than:
struct foo
{
// ...
};
> (and another case I note below)
> and class when not, there is a more serious reason.
>
> Lets's suppose I have
>
> struct Base
> {
> // virtual declarations.
> };
>
> Now I write some code, in foo.cpp
>
> #include "base.h";
> #include "foo.h"
>
> void foo(const Base & base)
> {
> // ...
> }
>
> and in foo.h
>
> void foo(const Base &);
>
> But I need a forward declaration of Base before that (no point including
> base.h).
> And the natural thing to use is
>
> class Base;
>
> However the last compiler I ran that code (or something similar) through
> gave
> me a warning that I'd mixed class and struct. And warnings are not good,
> it's generally recognised as good style to avoid them.
In the first place, that's a useless warning, since there is no
difference between a class and a struct. They're the same thing. The
keywords just introduce different default access levels, when used to
begin a definition.
In the second place, your compiler may not be configured in a sane way.
GCC, with the warnings cranked up, produces no such warning, nor
should it.
In the third place, if you really just want to be consistent, the thing
to change is the forward declaration, not the definition. The following
two declarations are semantically identical:
class base;
struct base;
In the fourth place, forward declarations smell bad. There's rarely any
good reason to start declaring code to work with classes whose
definitions have not even been seen.
> While on this topic there is another problem, which is if Base is actually
> a typedef, which doesn't forward declare well (something that could do
> with fixing).
It doesn't need to be "fixed," because it isn't broken. If you need to
work with a type that hasn't been defined yet, you can easily give it a
name by making it a template parameter. That's the right thing to do.
Then, you don't have to care whether it's a class name, a typedef, or a
primitive type.
> Currently also defining a base_fwd.h may be the least bad
> solution
> to that. Of course you could also do that just to specify struct Base, but
> that
> I think would be the worst idea in this posting.
You're digging yourself into a hole for no apparent reason, then
yelling: "See, I told you shovels were dangerous!"
It's unnecessary to make the header code compatible with C++ without any
particular reason.
> It's like when designing a door to your house: even if you and your wife
> are both short people (short people, short people! :-)[1]) you design
> that door so that other people can just walk in without risking banging
> their head.
That depends on the header. If the header is meant to be used in C++
code, then there are plenty of other issues that need to be taken into
account, as well. If, OTOH, the header is meant only to be used from C,
then why waste mind-space trying to write in a shared subset with some
other language? Should we all start avoiding variables called "id",
just in case we ever need source compatibility with Objective-C++?
Agreed, not a good idea to add unnecessary work for dubious future return.
But it's no work at all avoiding an obvious incompatibility.
So it's just poor craftsmanship, indicative of general incompetence, to have
that particular incompatibility.
>> It's like when designing a door to your house: even if you and your
>> wife are both short people (short people, short people! :-)[1]) you
>> design that door so that other people can just walk in without risking
>> banging their head.
>
> That depends on the header. If the header is meant to be used in C++
> code, then there are plenty of other issues that need to be taken into
> account, as well. If, OTOH, the header is meant only to be used from C,
> then why waste mind-space trying to write in a shared subset with some
> other language?
There's no extra work in avoiding the keyword 'class'.
And even a case where you absolutely know the code will only be used with a C
compiler, avoiding a keyword like 'class' helps to establish a general coding
style that promotes compatibility for other later code, which is good.
> Should we all start avoiding variables called "id",
> just in case we ever need source compatibility with Objective-C++?
Uhm, there's a good argument that no-one should be a house-painter, cause if
everyone chose to be house-painters, well, bye bye food supply chain. :-)
Or in other words, the "all" argument is invalid, arguing against a position
that hasn't been advocated by anyone.
You can read more about it here: <url:
http://www.nizkor.org/features/fallacies/straw-man.html>.
Cheers & hth.,
- Alf
--
> In the third place, if you really just want to be consistent, the thing
> to change is the forward declaration, not the definition. The following
> two declarations are semantically identical:
>
> class base;
> struct base;
They may seem the same, and should be the same, but at least one
compiler has alway rejected it if it doesn't match the actual definition.
>
> In the fourth place, forward declarations smell bad. There's rarely any
> good reason to start declaring code to work with classes whose
> definitions have not even been seen.
Oh really? Guess Sutter shouldn't have recommended them on his GotD
site and his Exceptional C++ books.
Nonsense, why would you se anything else when there is nothing bu a
public interface?
--
Ian Collins
>>> Rather the reverse. virtual typically appears in abstract
>>> interfaces. Since those interfaces have no private members, they are
>>> often declared as structs.
>>
>> That I'd regard as poor style (although of course that doesn't mean it
>> may not often occur).
>
> Nonsense, why would you se anything else when there is nothing bu a
> public interface?
Because style guidelines often reserve 'struct' to mean "behaviorless data
bucket", where a pure virtual interface is the exact opposite - dataless behavior.
Put that guideline together with "all publics should appear at the top of a
class", and our industry is fated to forever write only class Foo{ public:...
Other people have pointed out features that would show, or suggest,
that the code was C++.
By way of contrast, if you have conversions from void * - for example
using malloc without a cast, as recommended in comp.lang.c - this
would show the code was not C++.
Can you state any technical reason for that guideline or is this yet
another irrational standard you like to harp on?
What happens when what used to be a "behaviorless data bucket" suddenly
gains behavior?
Is a "behaviorless data bucket" really an object that has enough
responsibility to survive?
Is a C language structure that has member function pointers a class or not?
Is this a class?
class X
{
int x;
friend ostream& operator<<(ostream&,X const&);
};
Is this less of a class?
struct X
{
int x;
};
ostream& operator<<(ostream&,X const&);
Is this a class?
class X
{
public:
int x;
X() : x(42) {}
};
>
> Put that guideline together with "all publics should appear at the top
> of a class", and our industry is fated to forever write only class Foo{
> public:...
Why put it together with the former? There's no reason to use 'class'
over 'struct' since they mean the same thing. The only important thing
is to chose which you're going to use since finding the declaration of
the class to check if its declared as struct or class is annoying.
That's simply caused by a language deficiency.
Frankly, the idea of "class" as a cohesive entity in C++ is a misnomer.
Classes in C++ are compound data types that have zero or more of the
following:
* state
* member functions
* functions that accept the object as a parameter
* template traits utilities that provide information about the object
etc, etc...
As I learned the other day, even a union is a "class" in C++.
Since the only difference between 'struct' and 'class' in C++ is default
permission, and it is more common to inherit publicly and write public
members first, it is more efficient and sensible to use the 'struct'
keyword for everything. This does two things:
1. saves us from the pointless typing of 'public' everywhere.
2. Points out uncommon inheritance by using keywords for the uncommon
permission rather than the common one.
The standards committee could do us all a favor and get rid of the
'class' keyword all together.
> Since the only difference between 'struct' and 'class' in C++ is default
> permission, and it is more common to inherit publicly and write public
> members first, it is more efficient and sensible to use the 'struct'
> keyword for everything.
"More efficient and sensible" is overstating the case. You're right
about publics coming first more often, but popularity doesn't make it a
good idea. I always put private members first, with fields coming
before the functions that use them. Nothing in my code ever refers to
anything that has not defined yet, except in specific situations on
large projects where there are build-related concerns. I've been doing
this in earnest for about a year, and so far, I'm very happy with it.
I'd have been happy with not introducing "class" in the first place, but
that genie's not going back in the bottle.
I do the same thing in terms of ordering functions, but hadn't
thought about it terms of data members preceding functions.
That sounds like a good idea and I think I'll work on changing
to that tomorrow.
> I'd have been happy with not introducing "class" in the first place, but
> that genie's not going back in the bottle.
How about dropping the use of "struct" and using "class" instead?
The semantics of "class" could then be changed to those of "struct."
I'm talking ideally. I think "class" is a more helpful term.
Brian Wood
Ebenezer Enterprises
www.webEbenezer.net
> On May 21, 8:00 am, S Claus <sa...@temporaryinbox.com> wrote:
>> Hi
>>
>> here is a question, just out of curiousity:
>>
>> If you are given a bunch of .c files, is there a way to recognize (by
>> just looking at them) whether the code in them is written in C or in
>> C+ +?
>>
>> What would you look for?
>>
>> Thanks in advance,
>
> Depends on the input set.
>
> #include <stdio.h> /* C header
> #include <iostream.h>
>
> class xyz {
<snip>
> friend family relatives;
> */
>
> int main()
> {
> printf("My C++ program \n");
> return 0;
> }
>
> Now?
I like this one better:
#include <stdio.h>
char* string =
"#include <iostream>\n"
"using namespace std;\n"
"int main()\n"
"{\n"
" cout << \"Hello World\" << endl;\n"
"}\n";
int main()
{
printf("My C++ program: \n%s", string);
return 0;
}
>
> I agree with Juha Nieminen. Thats the best.
>
> How will one determain if a given text is English, French or a mix? We
> keep looking for key words? No. Make an English read the text.
Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
If you're going to hold that opinion, despite the clear advantages
of forward declarations in saving compilation dependencies, there's
no point us discussing further.
We don't agree, so there's no point us arguing past each other. But I
would be interested in a page/section reference here (Third Edition
only, anything before that is obsoleted) as the obvious Section 12.3
that introduces abstract base classes uses class, not struct.
Developers should not be expected to convolute their code, just to
accommodate a single broken or misconfigured compiler that they aren't
even using.
>> In the fourth place, forward declarations smell bad. There's rarely
>> any good reason to start declaring code to work with classes whose
>> definitions have not even been seen.
>
> Oh really? Guess Sutter shouldn't have recommended them on his GotD
> site and his Exceptional C++ books.
He recommended it to decrease build times on very large projects.
Nowadays, we have good support for precompiled headers. A far bigger
hit to build time now is individuals including headers inconsistently,
or in varying order, among translation units. Defining types completely
before using them actually makes it easier to identify a common prefix
for a large set of TUs. If you haven't seriously considered precompiled
headers yet, then your build times definitely are not long enough for
Herb's point to come into play.
The one case I've seen where forward declarations make sense is when
their typenames exist only to be used as placeholders in metaprograms.
In this case, there is no definition corresponding to the declaration,
so matching the two is moot. For example:
http://www.boost.org/doc/libs/1_39_0/libs/fusion/doc/html/fusion/quick_start.html#id458029
I first saw it in Java. There's an interesting discussion of code
order, with a brief comparison of Java and C++, in the book Clean Code,
by Bob Martin. I don't entirely agree with his views, but he does make
some good points.
>> I'd have been happy with not introducing "class" in the first place, but
>> that genie's not going back in the bottle.
>
> How about dropping the use of "struct" and using "class" instead?
> The semantics of "class" could then be changed to those of "struct."
> I'm talking ideally. I think "class" is a more helpful term.
Agreed completely. At the least, class is an actual word (rather than
an abbreviation), and is one character shorter. The problem with that
removing struct would be breaking C compatibility. (Not that we can
realistically remove class now, either.)
Precompiled headers are meant for extra-project dependencies, not
intra-project dependencies. You'll find that your build times are
greatly increased for almost all changes, no matter how small, if you
violate this.
That's funny, because I generally do the same thing.
But not necessarily C, as many people use compiler extensions or ignore
warnings from their C++ compiler.
That is not the case.
> I'd have been happy with not introducing "class" in the first place,
> but that genie's not going back in the bottle.
I'd have been happy to keep struct only for POD use, for C
compatibility. Different strokes and all that.
Brian
Well, since you say it...I _must_ be wrong.
If that's the case then your structs can never contain std::string or
anything else that isn't also a POD. May as well not use them at all at
that point.
As I said, C compatibility. std::string is not compatible with C. They
would be used for common C/C++ libraries or ported code. So yes, not
used all that often.
Brian
We tune the contents of our precompiled headers to minimise build time.
Precompiled ones are processed much faster, but you end up with stuff in
the compilation unit that it doesn't need - which slows it down.
There's also the overhead of what happens when a file that is in your
precompiled header set changes - everything that uses the precompiled
header has to be rebuilt.
There's no fixed rule.
Andy
Which is why you want precompiled headers to contain references to
stable, extra-project dependencies and not intra-project dependencies
nor rarely used ones. Precompiled headers are NOT a replacement for
forward declarations.
> Precompiled ones are processed much faster, but you end up with stuff in
> the compilation unit that it doesn't need - which slows it down.
To avoid runaway dependencies, you should not use the everything-in-one-header
system. You would like a (meaningful) error message if you type in an identifier
that the current module should not know about.
>>> Precompiled headers are meant for extra-project dependencies, not
>>> intra-project dependencies. You'll find that your build times are
>>> greatly increased for almost all changes, no matter how small, if you
>>> violate this.
>>
>> That is not the case.
>
> Well, since you say it...I _must_ be wrong.
Whether you're wrong has nothing to do with whether I or anybody else
point it out.
This is C++. We have namespaces.
I've always written my classes that way. I find it much more natural to
look up the screen for declarations than down. We do this everywhere
else in our code, so why should class declarations be any different?
One could argue writing the public interface before the private data it
uses is akin to top posting.....
--
Ian Collins
Assigning the return of malloc (void*) to anything else is a error, not
a warning.
--
Ian Collins
Writing the public interface first puts the most interesting and
important information about an interface as the first thing you see.
Implementation details, such as private member variables, rarely need to
be accessed or read. One would prefer they not be in the interface at
all, and you can use pimpl's to make that happen, but this is C++ so we
must make do. If you are using a pimpl then it makes even less sense to
have that as the top most item of importance in a class declaration
since it's completely meaningless to the interface.
The most important information should be the first information available
whenever possible. Since we normally read top to bottom, the most
important information should be at top. With regard to class
declarations, the most important information is almost always its public
interface.
One could argue anything one wants but comparing apples to oranges
(English prose to C++) is always going to be a fallacious argument
unless you can show reason for considering them the same.
Maybe, but that's not required by the standard. The standard only
requires a diagnostic.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)
I agree with some of that, but not really the conclusion. If you
put data members first, you'll get used to the public interfaces
following the data members. It may be a case of "Last, but not
least."
> > That I'd regard as poor style (although of course that
> > doesn't mean it may not often occur).
> I got it from Bjarne Stroustrup, in The C++ Programming
> Language. It's not poor style.
Style is a matter of taste. I know a lot of people who consider
it poor style. I also know some (a minority, but it does
include some experts) who use it systematically: struct if all
members are public.
The only absolute rule here is to use whatever style the other
programmers in your company are using.
> Furthermore, it is very popular, which is the exact opposite
> of the main claim from your previous post (which you snipped).
I don't know how popular it is. Stroustrup uses it, but I've
not seen many others recommending it. The most frequent rule
seems to be either "use struct for PODS, class for everything
else", or "use struct if there are data members and they are
public, class for everything else". And there are doubtless
other reasonable rules.
> > Putting aside that the sole purpose of this is to
> > save a few keystrokes,
> "Save" a few keystrokes? That presumes that writing class,
> followed by public:, is somehow the natural order of things,
> and that using struct deviates from that order. That's
> ridiculous; if you don't have any private members, why use a
> keyword whose sole purpose is to make a struct's default
> access level private?
Because it is the accepted convention where you work.
Like most people (I think), I always start my classes with the
public members. (This is really a questionable policy, but so
many places I've worked in have had it that I tend to do it
automatically.) And still use class, although the first
elements are public. For better or for worse, the words
"struct" and "class" speak to the reader, and you want to use
one which tells the reader the truth, when interpreted as he
interprets it.
> > and keystrokes are cheap, and that it conflicts with about
> > the only useful reason to have both struct and class, to
> > allow struct to be used for basic C-style structs
> That's one possible convention, being your favorite does not
> make it "about the only useful reason."
> class foo
> {
> public:
> // ...
> };
> Is more verbose, and IMO no clearer, than:
> struct foo
> {
> // ...
> };
Clarity depends on the local conventions. If the local
convention says that "struct" means PODS, then using it for
anything else is less clear.
> > (and another case I note below) and class when not, there is
> > a more serious reason.
> > Lets's suppose I have
> > struct Base
> > {
> > // virtual declarations.
> > };
> > Now I write some code, in foo.cpp
> > #include "base.h";
> > #include "foo.h"
> > void foo(const Base & base)
> > {
> > // ...
> > }
> > and in foo.h
> > void foo(const Base &);
> > But I need a forward declaration of Base before that (no
> > point including base.h). And the natural thing to use is
> > class Base;
> > However the last compiler I ran that code (or something
> > similar) through gave me a warning that I'd mixed class and
> > struct. And warnings are not good, it's generally recognised
> > as good style to avoid them.
> In the first place, that's a useless warning, since there is
> no difference between a class and a struct. They're the same
> thing. The keywords just introduce different default access
> levels, when used to begin a definition.
> In the second place, your compiler may not be configured in a
> sane way. GCC, with the warnings cranked up, produces no such
> warning, nor should it.
Off hand, I can't find a compiler that warns about it, even with
the warnings cranked up.
In the very distant past, VC++ 6 didn't just warn, it treated it
as an error (IIRC). But seriously, VC++ 6 is decidedly
pre-standard, and while I don't think one should constantly run
to use the latest version of every compiler, there's really no
excuse for going to the opposite extreme, and using compilers
that are more than ten years old (and no longer supported by
their vendor).
> In the third place, if you really just want to be consistent,
> the thing to change is the forward declaration, not the
> definition. The following two declarations are semantically
> identical:
> class base;
> struct base;
The problem is that if the rule depends on the contents of the
class, and you change the contents (in a way that should be
transparent to the user), all client code has to be modified.
> In the fourth place, forward declarations smell bad. There's
> rarely any good reason to start declaring code to work with
> classes whose definitions have not even been seen.
Forward declarations reduce coupling and dependencies. They
should be used whenever possible. (Of course, if you use the
compilation firewall idiom, you don't even need the forward
declarations.)
> > While on this topic there is another problem, which is if
> > Base is actually a typedef, which doesn't forward declare
> > well (something that could do with fixing).
> It doesn't need to be "fixed," because it isn't broken. If
> you need to work with a type that hasn't been defined yet, you
> can easily give it a name by making it a template parameter.
> That's the right thing to do. Then, you don't have to care
> whether it's a class name, a typedef, or a primitive type.
But you have introduced significant extra complexity, for
nothing. And in the absense of export, significant extra
coupling. Templates are something to be avoided (except when
the alternatives are worse, of course).
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> > class base;
> > struct base;
> They may seem the same, and should be the same, but at least
> one compiler has alway rejected it if it doesn't match the
> actual definition.
The only compiler I know which rejected it hasn't been around
for seven or eight years. All of the current versions I have
access to accept it.
> > In the fourth place, forward declarations smell bad.
> > There's rarely any good reason to start declaring code to
> > work with classes whose definitions have not even been seen.
> Oh really? Guess Sutter shouldn't have recommended them on
> his GotD site and his Exceptional C++ books.
Actually, Sutter isn't alone here---he's basing his
recommendations on Lakos. For once, every expert I know seems
to be in agreement here.
> >>>> Rather the reverse. virtual typically appears in
> >>>> abstract interfaces. Since those interfaces have no
> >>>> private members, they are often declared as structs.
> >>> That I'd regard as poor style (although of course that
> >>> doesn't mean it may not often occur).
> >> Nonsense, why would you se anything else when there is
> >> nothing bu a public interface?
> > Because style guidelines often reserve 'struct' to mean
> > "behaviorless data bucket", where a pure virtual interface
> > is the exact opposite - dataless behavior.
> Can you state any technical reason for that guideline or is
> this yet another irrational standard you like to harp on?
Communicating information to the reader? That's the "technical
reason" behind most guidelines. (The compiler doesn't care if
we indent, either, or even if we put the entire class definition
on a single line. Readers do.)
> What happens when what used to be a "behaviorless data bucket"
> suddenly gains behavior?
You've broken client code expectations, so all client code has
to be re-reviewed, and probably updated.
> Is a "behaviorless data bucket" really an object that has
> enough responsibility to survive?
It depends on what you mean by "behaviorless data bucket", and
whether C compatibility is an issue.
> Is a C language structure that has member function pointers a
> class or not?
> Is this a class?
> class X
> {
> int x;
> friend ostream& operator<<(ostream&,X const&);
> };
It's not even usable, since it only has a default
constructor:-).
> Is this less of a class?
> struct X
> {
> int x;
> };
> ostream& operator<<(ostream&,X const&);
According to the language, they're both classes. A user will
doubtlessly use them in different ways, however.
> Is this a class?
> class X
> {
> public:
> int x;
> X() : x(42) {}
> };
> > Put that guideline together with "all publics should appear
> > at the top of a class", and our industry is fated to forever
> > write only class Foo{ public:...
> Why put it together with the former?
Because they're both common guidelines.
> There's no reason to use 'class' over 'struct' since they mean
> the same thing.
To the compiler. Not to the human reader.
[...]
> As I learned the other day, even a union is a "class" in C++.
According to the standard. In practice, there's is a clear
distinction between unions and other classes (and you can't
forward declare a union with "class" or "struct", or vice
versa).
> Since the only difference between 'struct' and 'class' in C++
> is default permission, and it is more common to inherit
> publicly and write public members first, it is more efficient
> and sensible to use the 'struct' keyword for everything.
Efficient in what sense. Although it pleases me to see that
finally someone has enough sense to use the word for something
other than runtime efficiency (since I'm sure you didn't mean
that), I would like to know what efficiency you are talking
about. Since you have two distinct keywords, it would seem to
me that "efficiency" argues in favor of giving them different
meanings, even if the language doesn't.
> This does two things:
> 1. saves us from the pointless typing of 'public' everywhere.
Whoopy do.
> 2. Points out uncommon inheritance by using keywords for the
> uncommon permission rather than the common one.
In practice, that rules seems little enough known that it makes
sense to always specify access in inheritance. At least, except
for demonstrations in standards discussions, I've never seen
anyone not specifying access in inheritance.
> The standards committee could do us all a favor and get rid of
> the 'class' keyword all together.
Or making class and struct mean two different things. Or doing
any other number of things which would in fact break all
existing C++ code.
I don't call that a favor.
> > I do the same thing in terms of ordering functions, but
> > hadn't thought about it terms of data members preceding
> > functions. That sounds like a good idea and I think I'll
> > work on changing to that tomorrow.
> I first saw it in Java.
Java's a significantly different language than C++. Java
doesn't allow good separation of code and specification to begin
with. For better or for worse (mostly for worse, IMHO, but
that's a different argument), a lot of C++ projects tend to use
header files for documentation. And in that case, it does make
a lot of sense to put the public members first.
> > "More efficient and sensible" is overstating the case.
> > You're right about publics coming first more often, but
> > popularity doesn't make it a good idea. I always put
> > private members first, with fields coming before the
> > functions that use them. Nothing in my code ever refers to
> > anything that has not defined yet, except in specific
> > situations on large projects where there are build-related
> > concerns. I've been doing this in earnest for about a year,
> > and so far, I'm very happy with it.
> I've always written my classes that way. I find it much more
> natural to look up the screen for declarations than down. We
> do this everywhere else in our code, so why should class
> declarations be any different?
Because in far too many shops, they don't write class
documentation before writing the class itself. And far too
often, the class definition, in the header file, is the only
documentation you have for the class.
As for the position on the screen, when I'm working, the
declarations are above the actual code where they are used.
They're in separate windows in gvim, so I can put them where
ever I want. (Since the two are in separate files to begin
with, I couldn't put them in the same window, even if I wanted.)
> One could argue writing the public interface before the
> private data it uses is akin to top posting.....
I don't really see the relationship. The code which uses the
declarations is not even in the same file.
[...]
> > One could argue writing the public interface before the
> > private data it uses is akin to top posting.....
> Writing the public interface first puts the most interesting
> and important information about an interface as the first
> thing you see.
In a well organized shop, the *only* thing I'll see of a class
is its documentation, unless I'm actually maintaining the class
(and even then, I won't look at the class definition itself
until I've understood the documentation).
Of course, in the real world, things aren't always that well
organized, and you're right.
> Implementation details, such as private member variables,
> rarely need to be accessed or read. One would prefer they not
> be in the interface at all, and you can use pimpl's to make
> that happen, but this is C++ so we must make do. If you are
> using a pimpl then it makes even less sense to have that as
> the top most item of importance in a class declaration since
> it's completely meaningless to the interface.
An interesting (maybe), although purely anecdotal data point:
when I use the compilation firewall idiom, the implementation
class often will be declared "struct", i.e.:
Toto.hh:
class Toto
{
public:
// ...
private:
class Impl ;
Impl* myImpl ;
} ;
Toto.cc:
struct Toto::Impl
{
// ...
} ;
But of course, it's not rare for the Impl class to contain
mainly public data as well.
> Maybe, but that's not required by the standard. The standard only
> requires a diagnostic.
Is the following a well-formed C++ program? I was under the impression
that it was not.
struct value_t { };
typedef value_t* value_pointer;
typedef void* void_pointer;
int main() {
value_pointer p = value_pointer( );
void_pointer q = p;
p = q;
}
> As for the position on the screen, when I'm working, the
> declarations are above the actual code where they are used.
> They're in separate windows in gvim, so I can put them where
> ever I want. (Since the two are in separate files to begin
> with, I couldn't put them in the same window, even if I wanted.)
:split
It's ill-formed. When the compiler encounters an ill-formed construct,
the language definition requires that the compiler issue a diagnostic. A
diagnostic is any message from an implementation-defined set of
messages. The language definition does not distinguish between warnings,
errors, or valentines. It also does not require compilers to refuse to
compile ill-formed code (that's the hook for compiler-specific
extensions: issue a diagnostic, then do the extension).
Or putting private members at the end is like putting footnotes or an
appendix at the end, since many readers aren't interested in them.
A long time ago I put private members first because my compiler couldn't
deal with (textually) forward references.
> :split
As if I didn't know:-). I actually use :split when dealing with
local classes (defined in the source file), just as you say.
Oh well, we all have off moments when we forget something vital,
that we know perfectly.
>> To avoid runaway dependencies, you should not use the
>> everything-in-one-header system. You would like a (meaningful) error
>> message if you type in an identifier that the current module should
>> not know about.
>
> This is C++. We have namespaces.
This being C++, there's only a short list of situations where they work
perfectly! Any port in a storm...
> >> Maybe, but that's not required by the standard. The
> >> standard only requires a diagnostic.
> > Is the following a well-formed C++ program? I was under the
> > impression that it was not.
> It's ill-formed. When the compiler encounters an ill-formed
> construct, the language definition requires that the compiler
> issue a diagnostic. A diagnostic is any message from an
> implementation-defined set of messages. The language
> definition does not distinguish between warnings, errors, or
> valentines.
It also does not say where that message appears. A perfectly
conforming implementation could define that message to be "The
guy who wrote this is an idiot", and the medium to be an email
to your boss. (Luckily, no place I've worked has used such a
compiler.)
There's also nothing which forbids a compiler from issuing a
diagnostic for perfectly legal code. GCC documents that
"Diagnostics consist of all the output sent to stderr by GCC"
(for C, anyway), which definitly includes warnings. And some of
those warnings are for perfectly legal code. (Depending on the
options, some are for perfectly normal and idiomatic code.)
So a compiler which always outputs a single "?", regardless of
the program it is compiling, is perfectly conformant, if it
documents that "?" is its implementation defined diagnostic.
(Note to that its undefined behavior if your program exceeds a
resource limit. So all a compiler has to do to be conform is to
set its resource limits ridiculously low, output "?", and be
done with it. A one line shell script, in sum.)
> It also does not require compilers to refuse to compile
> ill-formed code (that's the hook for compiler-specific
> extensions: issue a diagnostic, then do the extension).
In fact, what happens after the diagnostic is undefined
behavior. I once heard it suggested that the compiler could
define the diagnostic to be that the red light on your hard disk
lights up for 1 second per MB (back then). The result of the
undefined behavior happened to be that your hard disk was
reformatted.
All of the above is really meant in fun, of course. The
standard doesn't (and cannot) require that the compiler is in
any way usable, and the standard is only part of the "contract"
with the compiler. Quality of implementation issues do
intervene, really, and although I've seen some pretty bad
compilers in my time, none were actually perverse. (And I don't
loose any sleep over the possibility that my compiler might
reformat my hard disk if I fed it a ill-formed program.)
What are you talking about? They're extremely well supported, portable,
and useful. Namespaces are not "iffy."
Or something trivial, sure to be pointed out immediately by someone else. :)
> As for the position on the screen, when I'm working, the
> declarations are above the actual code where they are used.
> They're in separate windows in gvim, so I can put them where
> ever I want. (Since the two are in separate files to begin
> with, I couldn't put them in the same window, even if I wanted.)
So your compilers support export templates?
--
Ian Collins
--
Ian Collins
I don't dispute your assertions, but don't find your
conclusion persuasive.
> As for the position on the screen, when I'm working, the
> declarations are above the actual code where they are used.
> They're in separate windows in gvim, so I can put them where
> ever I want. (Since the two are in separate files to begin
> with, I couldn't put them in the same window, even if I wanted.)
>
> > One could argue writing the public interface before the
> > private data it uses is akin to top posting.....
>
> I don't really see the relationship. The code which uses the
> declarations is not even in the same file.
>
Don't forget about header only libraries like the Boost
Intrusive library --
http://www.boost.org/doc/libs/1_39_0/doc/html/intrusive.html.
No:-). But it's still quite possible (and generally
preferable) to put the template implementation in a separate
file; you just have to include that file from the header,
rather than compiling it separately. (And of course,
templates are a special case---most programmers shouldn't be
defining them anyway.)
Duh! So far though, there's been no argument from the poster that this
guideline does address communication. In fact, it is my argument that
it communicates falsehood.
>
>> What happens when what used to be a "behaviorless data bucket"
>> suddenly gains behavior?
>
> You've broken client code expectations, so all client code has
> to be re-reviewed, and probably updated.
Before change:
struct DataBucket
{
int x;
char q;
};
After change:
struct DataBucket
{
int x;
char q;
print();
};
I see no client breaking changes.
>> There's no reason to use 'class' over 'struct' since they mean
>> the same thing.
>
> To the compiler. Not to the human reader.
When in argument, the human rarely wins.
> > Communicating information to the reader? That's the
> > "technical reason" behind most guidelines.
> Duh! So far though, there's been no argument from the poster
> that this guideline does address communication. In fact, it
> is my argument that it communicates falsehood.
It communicates what the local conventions say it communicates.
Regardless of the local conventions, of course, it can be used
to lie, but that's a separate issue.
> >> What happens when what used to be a "behaviorless data
> >> bucket" suddenly gains behavior?
> > You've broken client code expectations, so all client code
> > has to be re-reviewed, and probably updated.
> Before change:
> struct DataBucket
> {
> int x;
> char q;
> };
> After change:
> struct DataBucket
> {
> int x;
> char q;
>
> print();
> };
> I see no client breaking changes.
And I see no real reason to change struct to class---it's still
a POD. And it can still be used as a data bucket.
Add a constructor, and the issue changes: algomerate
initialization is no longer valid, and there's no way to ensure
static initialization. In some conventions, that's sufficient
to change the "struct" to "class". (In the convention I use in
my own code, either all data members are private, or all are
public. I use class in the first case, and struct in the
second. If there are no data members, I'm somewhat ambivalent;
I'll generally use class if there are non-static member
functions, and struct otherwise.)
> >> There's no reason to use 'class' over 'struct' since they mean
> >> the same thing.
> > To the compiler. Not to the human reader.
> When in argument, the human rarely wins.
But there's no argument, since the compiler doesn't care.
> And I see no real reason to change struct to class---it's still
> a POD. And it can still be used as a data bucket.
First, that's not what the poster to whom I replied stated. They didn't
say POD. If you want to change the topic that's fine, but don't pretend
that's a refutation.
Second, 'class' can also be a POD. PODness actually depends very little
on anything that should be considered high level enough to be deciding
code standard issues. It isn't a matter that depends solely on design
semantics but on low-level language semantics. If you decide to make
all PODs structs and all non-PODs classes, you'll find that a lot of
structures that people would normally consider classes (in an OO sense)
need to be structs.
It is better to just consider them the same thing, since they in fact are.
>
> Add a constructor, and the issue changes: algomerate
> initialization is no longer valid, and there's no way to ensure
> static initialization.
The declaration of a struct or class is sufficiently removed from usage
sites in most cases to make the distinction insufficient to
communicating this difference.
>>>> There's no reason to use 'class' over 'struct' since they mean
>>>> the same thing.
>
>>> To the compiler. Not to the human reader.
>
>> When in argument, the human rarely wins.
>
> But there's no argument, since the compiler doesn't care.
That IS the argument. Human says it matters, compiler says it doesn't.
Compiler wins. How does it win? Because you'll find it provides no
indication you're using struct/class in a manner that violates whatever
distinction you have made up. A 'struct' that has "become" a 'class'
can slip by the compiler with no warning whatsoever.
> If you are given a bunch of .c files, is there a way to recognize (by
> just looking at them) whether the code in them is written in C or in C+
> +?
>
> What would you look for?
The file name. Why would a C++ file have a .c extension to begin with?
sherm--
--
My blog: http://shermspace.blogspot.com
Cocoa programming in Perl: http://camelbones.sourceforge.net
> James Kanze wrote:
>
>>>>> There's no reason to use 'class' over 'struct' since they mean
>>>>> the same thing.
>>
>>>> To the compiler. Not to the human reader.
>>
>>> When in argument, the human rarely wins.
When in argument between a compiler and a human reviewer, the one that
takes the strictest view wins.
If the human reviewer imposes more requirements on the code than the
compiler, the human invariably wins (if only because he refuses to sign-
off on your code).
>>
>> But there's no argument, since the compiler doesn't care.
>
> That IS the argument. Human says it matters, compiler says it
> doesn't.
> Compiler wins. How does it win? Because you'll find it provides no
> indication you're using struct/class in a manner that violates
> whatever
> distinction you have made up. A 'struct' that has "become" a 'class'
> can slip by the compiler with no warning whatsoever.
By that reasoning, this is perfect code, because the compiler accepts
it:
#include<stdio.h>
int main(int,const char**v){goto L8;L2:return 99;L3:if((*v)[0])goto
L6;else goto L2;L4:v[0]++;L5:goto L3;L6:putchar(**v);goto
L4;L8:v[0]="hello, world\n";goto L5;}
It compiles cleanly and works as expected, so there can not be any
hindrance in putting this code in the production archive. Or is there?
Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
The fact that there are pointless standards does not legitimate
pointless standards. The argument is not about whether or not some code
will pass someone's silly idea of what should be done, but whether they
should be imposing this meaningless standard.
>
>>> But there's no argument, since the compiler doesn't care.
>> That IS the argument. Human says it matters, compiler says it
>> doesn't.
>> Compiler wins. How does it win? Because you'll find it provides no
>> indication you're using struct/class in a manner that violates
>> whatever
>> distinction you have made up. A 'struct' that has "become" a 'class'
>> can slip by the compiler with no warning whatsoever.
>
> By that reasoning, this is perfect code, because the compiler accepts
> it:
>
> #include<stdio.h>
> int main(int,const char**v){goto L8;L2:return 99;L3:if((*v)[0])goto
> L6;else goto L2;L4:v[0]++;L5:goto L3;L6:putchar(**v);goto
> L4;L8:v[0]="hello, world\n";goto L5;}
>
> It compiles cleanly and works as expected, so there can not be any
> hindrance in putting this code in the production archive. Or is there?
I'll clue you into the difference.
The above is pretty much illegible. However, the scope of the problem
is rather limited. If there are functions elsewhere that have adequate
formatting, they are not impacted by the problem of reading main(). As
far as working on that code is concerned, main is not a problem since
main is not meant to communicate anything beyond itself.
Those claiming 'struct' needs to be used to communicate some sort of
whatever (nobody seems to agree on what) are primarily claiming that it
is meant to communicate issues that ARE meant to go beyond the scope of
declaration. You can be miles away from the part of the code meant to
inform you of something and be completely unaware of this.
In other words, the struct problem is one of point A attempting to
communicate something to point B, with nothing at point B to indicate
this communication is taking place; there's a disconnect. Your screwed
up main function is not such a situation.
Claiming that apples should all be red because oranges are orange is not
convincing.
Maybe. Or maybe there was a legitimate reason. Perhaps the code was
subtly incompatible with C++ in some way, and using "class" as an
identifier prevents someone from accidentally using it from C++.
(I'm not saying it's likely, but it's conceivable.)
> It's like when designing a door to your house: even if you and your
> wife are both short people (short people, short people! :-)[1]) you
> design that door so that other people can just walk in without risking
> banging their head.
>
> Or, I would, if I were that short and were designing a door.
Ah, but if you don't like tall people ...
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Some C++ files have a ".C" extension, and some operating systems /
file systems doesn't distinguish between upper and lower case. And
using ".h" for C++ headers is more common than using ".c" for C++
source files.
There is no reliable algorithm for doing this. For one thing, the
same source file might be valid both as C and as C++, either because
it doesn't happen to use any of the unique features of either language
or because it was deliberately designed to be compatible, perhaps by
using #ifdef __cplusplus". And a lot of C code is valid C++ anyway,
though probably not idiomatic C++.
And a sufficiently perverse programmer might write code that's
intended to look like one language when it's not:
cout << x << '\n';
looks like C++ until you realize that cout is declared as an unsigned
int. (Which is still valid C++.)
Note that // comments don't distinguish between C and C++; C99 allows
them, and many pre-C99 compilers support them as an extension.
Most of the things I'd look for have already been mentioned:
Standard header names
>> and << for I/O
::
new, delete
Why do you assume code to have different formatting than the function I
presented above? Formatting (and variable naming) don't convey any more
meaning to the compiler than the difference between class and struct
(which you insist is non-existent).
Rules about writing readable code are just pointless standards, because
the compiler can't enforce them.
<snip>
>
> Claiming that apples should all be red because oranges are orange is
> not convincing.
Claiming you can not differentiate between red apples and green apples,
because they are all apples is equally non-convincing.
As I see it, attaching additional meaning to class or struct is a style
issue, similar to naming conventions and brace placement.
There is no absolute right or wrong, but it helps if you follow the
local conventions.
> Maybe. Or maybe there was a legitimate reason. Perhaps the code was
> subtly incompatible with C++ in some way, and using "class" as an
> identifier prevents someone from accidentally using it from C++.
>
> (I'm not saying it's likely, but it's conceivable.)
If the header is truly incompatible with C++, I would have used a much
stronger signal to indicate that. Something like
#ifdef __cplusplus
#error This header can't be used in C++ code
#endif
>
>> It's like when designing a door to your house: even if you and your
>> wife are both short people (short people, short people! :-)[1]) you
>> design that door so that other people can just walk in without
>> risking banging their head.
>>
>> Or, I would, if I were that short and were designing a door.
>
> Ah, but if you don't like tall people ...
>
Then you would design a door that looks too small for those tall people.
You would not paint a large door around your small one to fool those
large people (unless you were malicious, but then you would also hang up
a sign saying 'tall people welcome').
>>> #include<stdio.h>
>>> int main(int,const char**v){goto L8;L2:return 99;L3:if((*v)[0])goto
>>> L6;else goto L2;L4:v[0]++;L5:goto L3;L6:putchar(**v);goto
>>> L4;L8:v[0]="hello, world\n";goto L5;}
>>>
>>> It compiles cleanly and works as expected, so there can not be any
>>> hindrance in putting this code in the production archive. Or is
>>> there?
>> I'll clue you into the difference.
>>
>> The above is pretty much illegible. However, the scope of the problem
>> is rather limited. If there are functions elsewhere that have
>> adequate
>> formatting,
>
> Why do you assume code to have different formatting than the function I
> presented above? Formatting (and variable naming) don't convey any more
> meaning to the compiler than the difference between class and struct
> (which you insist is non-existent).
Sigh. I was attempting to explain the difference between something
meant to convey communication as you read it, and something meant to
convey communication in some separate area of code. Any formatting
problem with main is a problem right there, not somewhere else. Using
the struct keyword to communicate PODhood or some other thing that has
wide reaching meaning is not sufficient toward that end because the call
site does not have that information anywhere.
>
> Rules about writing readable code are just pointless standards, because
> the compiler can't enforce them.
Wrong, but go ahead and feel that way. However, rules about
"readability" that have nothing to do with readability, do not help with
readability, and can be broken too easily without any warning...that
require editing the project in multiple locations in order to keep up
with this "readability", are more than just pointless...they're stupid.
>
> <snip>
>> Claiming that apples should all be red because oranges are orange is
>> not convincing.
>
> Claiming you can not differentiate between red apples and green apples,
> because they are all apples is equally non-convincing.
>
> As I see it, attaching additional meaning to class or struct is a style
> issue, similar to naming conventions and brace placement.
There are several differences. Naming conventions follow objects
around. A naming convention is at any site that the object is used.
Not so with declaration keywords. If you're going to insist that
PODness needs to be communicated to users, then use your naming
conventions to dictate that; call pods podObject or something.
No, I wouldn't recommend that. Names should indicate purpose, not type.
But hey, everyone wants to know if this thing's a POD or not and want
that indicated in the type somehow even if it really isn't.
Brace placement is also a stupid thing to argue about but at least it is
less so than using 'struct' to carry meaning it isn't meant to carry.
It at least affects local code structure and readability.
> There is no absolute right or wrong, but it helps if you follow the
> local conventions.
I never said there was an absolute right or wrong. I suggested that the
idea of forcing yourself to use class instead of struct was uncalled for
and this seems to have ruffled many feathers, including yours.
> Sigh. I was attempting to explain the difference between something
> meant to convey communication as you read it, and something meant to
> convey communication in some separate area of code. Any formatting
> problem with main is a problem right there, not somewhere else. Using
> the struct keyword to communicate PODhood or some other thing that has
> wide reaching meaning is not sufficient toward that end because the
> call site does not have that information anywhere.
It seems we are talking at slight cross-angles, because I agree that
communication PODness by using struct is a failed strategy.
What I try to communicate when using struct is one of two things
1. The code must be usable in both C and C++
2. The type has no class-invariant and is regarded as a loose
aggregation of members. Direct access to the data members (without using
an accessor function) is explicitly allowed. There are no further
restrictions on the type (so having a non-POD member, a constructor, a
member function, etc. is no problem).
Which of the two cases holds for the structure follows from the
documentation.
In the second case, the struct keyword is meant to serve as a reminder,
first to the maintainer that fiddling with the data members constitutes
an interface change and that adding a class-invariant requires updating
all the clients. And secondly to the clients that the public access on
the data members is intentional and that you can directly access them.
As you can see, the struct keyword as wide reaching effects, but the
place where it matters most is in close proximity to where the keyword
appears in the code.
>
>>
>> Rules about writing readable code are just pointless standards,
>> because the compiler can't enforce them.
>
> Wrong, but go ahead and feel that way. However, rules about
> "readability" that have nothing to do with readability, do not help
> with
> readability, and can be broken too easily without any warning...that
> require editing the project in multiple locations in order to keep up
> with this "readability", are more than just pointless...they're
> stupid.
I agree. That is why my 'rules' about usage of the struct keyword are
not about readability. They are about the contract between the
author/maintainer of the class or struct and their users and are
primarily meant as a quick visual reminder to the maintainer that
something special is going on.
> What I try to communicate when using struct is one of two things
> 1. The code must be usable in both C and C++
Admittedly, I couldn't care less about compatibility with C.
> 2. The type has no class-invariant and is regarded as a loose
> aggregation of members. Direct access to the data members (without using
> an accessor function) is explicitly allowed.
Interesting. I've felt no need to use anything but access permission
keywords to express access permission. IMHO, using access permission
keywords to express access permission is the better approach since it is
the method directly supported by the language in addition to expressing
exactly what you want to express.
> Which of the two cases holds for the structure follows from the
> documentation.
> In the second case, the struct keyword is meant to serve as a reminder,
> first to the maintainer that fiddling with the data members constitutes
> an interface change and that adding a class-invariant requires updating
> all the clients. And secondly to the clients that the public access on
> the data members is intentional and that you can directly access them.
I suppose if you don't already follow the principle that direct public
access to internal values is a bad thing, you might need to find ways to
communicate when you adamantly want to maintain it.
As to the assertion that the public access on data members is
intentional, that just might be a good argument for using the 'class'
keyword for these cases since it would *require* the author to write
'public:' in order to explicitly state public access...in a 'struct'
they can forget and the maintainer can't be sure if they did or not
(unless they are intimately familiar with your alteration of the
semantics of other keywords in the language).
> Bart van Ingen Schenau wrote:
>
>> What I try to communicate when using struct is one of two things
>> 1. The code must be usable in both C and C++
>
> Admittedly, I couldn't care less about compatibility with C.
>
>> 2. The type has no class-invariant and is regarded as a loose
>> aggregation of members. Direct access to the data members (without
>> using an accessor function) is explicitly allowed.
>
> Interesting. I've felt no need to use anything but access permission
> keywords to express access permission. IMHO, using access permission
> keywords to express access permission is the better approach since it
> is the method directly supported by the language in addition to
> expressing exactly what you want to express.
Well, using struct and access specifiers is not an either/or
proposition, but and/and.
The struct keyword signals that the type deviates from the established
best practices (for that project). Giving public access to member
variables is just the most common deviation.
>
>> Which of the two cases holds for the structure follows from the
>> documentation.
>> In the second case, the struct keyword is meant to serve as a
>> reminder, first to the maintainer that fiddling with the data members
>> constitutes an interface change and that adding a class-invariant
>> requires updating all the clients. And secondly to the clients that
>> the public access on the data members is intentional and that you can
>> directly access them.
>
> I suppose if you don't already follow the principle that direct public
> access to internal values is a bad thing, you might need to find ways
> to communicate when you adamantly want to maintain it.
>
> As to the assertion that the public access on data members is
> intentional, that just might be a good argument for using the 'class'
> keyword for these cases since it would *require* the author to write
> 'public:' in order to explicitly state public access...in a 'struct'
> they can forget and the maintainer can't be sure if they did or not
> (unless they are intimately familiar with your alteration of the
> semantics of other keywords in the language).
When people are in the habit of writing
class X {
public:
// public members
private:
// private members
};
then by leaving out the access specifier 'private', it becomes obscured
if the public access to the data members was intentional or an oversight
in adding the correct access specifier.
You may argue that the private members should be listed first, but in my
experience that is simply not how classes are written.
And before a maintainer even dares to touch the code, he/she should be
familiar with the relevant project documentation, which includes the
coding guidelines where the convention for using class or struct is
explained.
...
> And before a maintainer even dares to touch the code, he/she should be
> familiar with the relevant project documentation, which includes the
> coding guidelines where the convention for using class or struct is
> explained.
I can't help but notice that everyone's argument for using struct to
signal some meaning it doesn't have always ends up coming back to some
existing practice or documentation that already assumes the conclusion.
A circular argument through authority so to speak.
I'm not arguing that one ignores guidelines that someone decided to put
in a project. I'm arguing that when you're in charge of making
guidelines you don't put such a meaningless and easily broken one in
your guidelines. I'm arguing that it makes no sense, *inherently*, to
do so.
> I can't help but notice that everyone's argument for using struct to
> signal some meaning it doesn't have always ends up coming back to some
> existing practice or documentation that already assumes the
> conclusion.
> A circular argument through authority so to speak.
>
> I'm not arguing that one ignores guidelines that someone decided to
> put
> in a project. I'm arguing that when you're in charge of making
> guidelines you don't put such a meaningless and easily broken one in
> your guidelines. I'm arguing that it makes no sense, *inherently*, to
> do so.
I can't help but notice that you advocate a 'free for all' coding
attitude where only the compiler is the final arbiter on what is
acceptable and what not.
The entire reason for having coding guidelines at all is to document
those conventions that can NOT be checked by the compiler and are hence
easily broken.
We started this exchange with this program (reformatted):
#include<stdio.h>
int main(int, const char**v)
{
goto L8;
L2: return 99;
L3: if((*v)[0])
goto L6;
else
goto L2;
L4: v[0]++;
L5: goto L3;
L6: putchar(**v);
goto L4;
L8: v[0]="hello, world\n";
goto L5;
}
I would agree with you that this code is hopelessly unmaintainable, but
maintainability is too subjective a term to be able to use it in rooting
out bad code.
To keep bad code out of your project, you need some restrictions and
conventions on how the C++ language can be used within the project that
go beyond what a compiler is required to diagnose.
Your argument against assigning a restricted meaning to struct is that
the compiler can't help you in enforcing that restricted meaning.
My counter-argument is that with such an attitude, you also can not in a
meaningful manner impose a naming convention or restrict the use of
dangerous/unmaintainable constructs (like goto).
This does not mean that you *must* follow all these guidelines, just
that if you want to follow one of them, your argument why struct can't
have a restricted meaning falls down. An argument like "I don't like
such a rule in my project" would still be valid not to implement it in
your guidelines.
And don't come with the local vs remote effect argument, because that
would only prove you have not been paying attention.
> Your argument against assigning a restricted meaning to struct is that
> the compiler can't help you in enforcing that restricted meaning.
Again, you misrepresent my argument. It seems on purpose since I quite
explained it earlier.
It's too hard to track what everyone whats to use this struct keyword
for. It seems that among the various proponents for using struct only
for some something or other, but never classes, can't agree on what that
something or other is. This speaks volumes toward its utility in
expressing any one of these things.
The point of my argument is that 'struct' and 'class' mean exactly the
same thing in the C++ language. There is no inherent reason to prefer
'class' over 'struct'. The various purposes proposed range from
ill-defined to overly strict and difficult to enforce. Since you'll get
no help from the compiler, and the things you want to enforce need to be
tracked by the individual in ways that have nothing to do with 'struct'
vs. 'class', the use of these keywords to hold extra meaning seems to be
quite ill-advised.
You're taking this statement and inverting it incorrectly. Just because
THIS non-compiler enforced semantic issue is ill-advised does not mean
that ALL are. I gave quite concrete reasons why I think attempting to
force people to use 'struct' only for "non-class" objects is
questionable at best, and why those same arguments can't be applied to
code formatting and standards in general.
You say you want C compatibility, but this does not preclude not using
struct for classes.
You say you want to ensure this or that, but this does not preclude not
using struct for classes.
All the various purported reasons given so far seem to me to be better
expressed in comments. "This object needs to be C compatible," for
instance (which might also be expressed with extern "C"). The 'struct'
keyword does not seem sufficient to express what is desired in any of
these cases, nobody agrees what it should be expressing, and the use of
'struct' in modern C++ texts for objects that could certainly be viewed
as class-like in nature is quickly becoming common.
The OP stated, as point of fact, that you should never use 'struct' for
class objects and I stand utterly unconvinced so far that this is a
logical assumption. Frankly, the best argument for using 'class'
instead of struct is to force the very verbosity that the OP was
complaining about originally. I haven't seen a need to issue such a
constraint in my team.
I'm not saying that coding standards are useless (we have many), just
this one. No amount of misrepresenting of that argument will change it.