Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A Standard Proposal: Remove forward declaration requirements

76 views
Skip to first unread message

Rick C. Hodgin

unread,
Jul 26, 2017, 3:42:34 PM7/26/17
to
This is the year 2017. Computers are powerful, and advanced and have
algorithms for all kinds of compiler needs developed. The time of any
component of a modern compiler REQUIRING forward declarations is long
since past, save the needs of legacy software that was written for a
system with that expectation.

-----
What can be done to initiate a grass roots movement to remove the need
for having forward declarations in upcoming C and C++ Standards?

And just to be clear, I'm not saying we should remove the forward-
declaration ability altogether, but just add a new option which
removes the requirement of having it.

I think some kind of compiler switch which disables the forward-
declaration requirement, allowing an additional pass to be run on
source code to resolve unknown references would be desirable.

Thank you,
Rick C. Hodgin

Lynn McGuire

unread,
Jul 26, 2017, 4:56:04 PM7/26/17
to
In C++'s strong typing system, how would you get rid of forward
declarations ? I see them as a necessary evil as we have about 22
classes forward declared in our main app.

Thanks,
Lynn

Rick C. Hodgin

unread,
Jul 26, 2017, 5:45:02 PM7/26/17
to
On 7/26/2017 4:55 PM, Lynn McGuire wrote:
> On 7/26/2017 2:42 PM, Rick C. Hodgin wrote:
>> This is the year 2017. Computers are powerful, and advanced and have
>> algorithms for all kinds of compiler needs developed. The time of any
>> component of a modern compiler REQUIRING forward declarations is long
>> since past, save the needs of legacy software that was written for a
>> system with that expectation.
>>
>> -----
>> What can be done to initiate a grass roots movement to remove the need
>> for having forward declarations in upcoming C and C++ Standards?
>>
>> And just to be clear, I'm not saying we should remove the forward-
>> declaration ability altogether, but just add a new option which
>> removes the requirement of having it.
>>
>> I think some kind of compiler switch which disables the forward-
>> declaration requirement, allowing an additional pass to be run on
>> source code to resolve unknown references would be desirable.
>
> In C++'s strong typing system, how would you get rid of forward
> declarations ? I see them as a necessary evil as we have about 22
> classes forward declared in our main app.

I don't propose getting rid of forward declarations, but enabling a
switch that would allow them to not be required when the switch is
in use.

For many projects, it would only be a matter of allowing the def-
inition for the thing you're referencing to be made somewhere in
source code rather than already in source code. And when parsing
on the first pass, you don't really do any parsing other than to
lex and identify things that are known, though you could also save
that for the next pass once you've loaded everything that may be
resolved later in code.

Ben Bacarisse

unread,
Jul 26, 2017, 6:18:40 PM7/26/17
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:
<snip>
> I don't propose getting rid of forward declarations, but enabling a
> switch that would allow them to not be required when the switch is
> in use.

No change in the standard is required for that. And if the requirement
*were* removed from the standard it could not mandate a switch or any
other extra-linguistic mechanism for it. There might be a pre-defined
macro that code could test, or a pragma to turn the option on or off,
but nothing outside of C itself. The C standard has no jurisdiction
there.

<snip>
--
Ben.

Ben Bacarisse

unread,
Jul 26, 2017, 6:37:30 PM7/26/17
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:
<snip>

> What can be done to initiate a grass roots movement to remove the need
> for having forward declarations in upcoming C and C++ Standards?

Implement it in a widely used compiler (gcc and clang are two obvious
choices) and when/if it is seen to be useful and accepted a proposal
would stand a reasonable chance of success. And even if it were to
fail, the community would get the benefit (if any) from the feature.

<snip>
--
Ben.

Rick C. Hodgin

unread,
Jul 26, 2017, 8:29:52 PM7/26/17
to
On 7/26/2017 8:15 PM, jacobnavia wrote:
> Le 27/07/2017 à 01:54, bartc a écrit :
>> I mean code like this:
>>
>> int main(void) {
>> int a;
>>
>> int A[sizeof(fn)*100];
>>
>> switch (a){
>> case sizeof(fn()):
>> break;
>> }
>> }
>>
>
> That's a contrieved example... But the more I think about it, it looks
> uglier and uglier...
>
> :-)
>
> int c = undeclared(42);
>
> Many conversions are possible, depending on the result type of
> "undeclared". The intermediate code would need to have some
> "MaybeConvert" operations inserted. When actually generating code those
> conversions would be eliminated, or not.
>
> But it could be very unwidely.
>
> Suppose a 3000 line GUI program that ends with
>
> #include <windows.h>
>
> UGGGGGG!!!!!

While such a thing would be theoretically possible, why code like
that? Just because an ability exists doesn't mean it should be
exploited in such a way.

My goals are primarily to resolve issues of interbred include
files which contain definitions referenced in other include files.

If you have a large enough system with enough structs or classes
that reference one other in other header files in a crossover manner,
it becomes increasingly difficult to ensure things are defined in
the right order so you can reference members rather than just ptrs.

I have spent a great deal of time in my Visual FreePro, Jr. project
creating files that are loaded ahead of others, so they can refer-
ence the members of things defined in other files. I have done
this because I have a file that handles lexing, but it also knows
about bitmaps, and the bitmap class handles bitmaps, but it also
knows about lexing components so they can be rendered properly
during debugging, etc.

This type of interbred library mandates something more than what
C/C++ offer in the way of forward declarations. With just that
one relaxation, I would be able to include my bitmaps.h file,
and my lexing.h file, and even though they reference components
in each other, neither would produce an error, and no special or
fancy programming workarounds would be required.

David Brown

unread,
Jul 27, 2017, 3:29:26 AM7/27/17
to
On 26/07/17 23:44, Rick C. Hodgin wrote:
> On 7/26/2017 4:55 PM, Lynn McGuire wrote:
>> On 7/26/2017 2:42 PM, Rick C. Hodgin wrote:
>>> This is the year 2017. Computers are powerful, and advanced and have
>>> algorithms for all kinds of compiler needs developed. The time of any
>>> component of a modern compiler REQUIRING forward declarations is long
>>> since past, save the needs of legacy software that was written for a
>>> system with that expectation.
>>>
>>> -----
>>> What can be done to initiate a grass roots movement to remove the need
>>> for having forward declarations in upcoming C and C++ Standards?
>>>
>>> And just to be clear, I'm not saying we should remove the forward-
>>> declaration ability altogether, but just add a new option which
>>> removes the requirement of having it.
>>>
>>> I think some kind of compiler switch which disables the forward-
>>> declaration requirement, allowing an additional pass to be run on
>>> source code to resolve unknown references would be desirable.
>>
>> In C++'s strong typing system, how would you get rid of forward
>> declarations ? I see them as a necessary evil as we have about 22
>> classes forward declared in our main app.
>
> I don't propose getting rid of forward declarations, but enabling a
> switch that would allow them to not be required when the switch is
> in use.

The standards don't have "compiler switches" - that is something an
implementation has. There is nothing to stop an implementation having
such a switch if it wants, assuming it can be made to work properly.

This is, in fact, an essential requirement for getting such a change
into the C or C++ standards - it is expected that there be one or more
/major/ compiler implementations of a feature that have undergone
testing, evaluation and refinement. (By "major", I mean tools like gcc,
clang, MSVC - not something like Jacob's compiler, fine tool though it
may be. You need a large user base.)

>
> For many projects, it would only be a matter of allowing the def-
> inition for the thing you're referencing to be made somewhere in
> source code rather than already in source code. And when parsing
> on the first pass, you don't really do any parsing other than to
> lex and identify things that are known, though you could also save
> that for the next pass once you've loaded everything that may be
> resolved later in code.
>

At first glance, I think it is likely that forward declarations could be
made redundant - though I certainly have not given it serious thought.
Basically, the compiler could first read through the file and whenever
it finds a function definition, class definition, struct definition,
etc., it could construct an appropriate forward declaration. Then it
could artificially insert these into the code and compile as normal.

It would be more of an inconvenience, I think, for other tools that
parse code in a simpler way, such as highlighting editors.

I suppose it all depends on your style of coding, but personally I
rarely need forward declarations - so they are no bother to me. The
only thing that annoys me about forward declarations is that some people
insist on putting a list of them at the start of their files, regardless
of their need - such lists can get inconsistent and are a maintenance
irritation.


bartc

unread,
Jul 27, 2017, 6:07:28 AM7/27/17
to
On 27/07/2017 08:29, David Brown wrote:

> At first glance, I think it is likely that forward declarations could be
> made redundant - though I certainly have not given it serious thought.
> Basically, the compiler could first read through the file and whenever
> it finds a function definition, class definition, struct definition,
> etc., it could construct an appropriate forward declaration. Then it
> could artificially insert these into the code and compile as normal.

It wouldn't need to be that crude. That might be what a separate tool
would do to transform such C code into conventional C. (Actually,
exactly what I used once, which identified local and export functions
given stylised function definitions, and wrote out .cl and .cx header
files respectively.)

> It would be more of an inconvenience, I think, for other tools that
> parse code in a simpler way, such as highlighting editors.

This is not parsing, which stays the same.

If it wants to colour different kinds of identifiers in different ways,
then yes it might need to look ahead in the file, but it is not exactly
a trivial task anyway as it needs to resolve variables, typedefs,
macros, enum names, and labels as well as function names. (How does such
an editor manage with C++?)

> I suppose it all depends on your style of coding, but personally I
> rarely need forward declarations - so they are no bother to me.

I think everyone does unless they pay attention to the exact ordering of
functions in a file.

You're writing function F, and it calls G. Now you have to write G, but
you have to make sure it precedes F (so you can no longer read your code
top-down).

You now modify F and it calls a new function H, and H is inserted
between G and F.

Later, you modify G to call H too. But now that won't work, because G
won't see H. You have to now move H to just before G, or create (and
have to maintain) a forward declaration of H.

You can try inserting every new function at the top of the file, but
then, such a function may need to call an existing function, so that
won't work.

Or, you write function F which calls G which then calls F; where does
each go?

This stuff happens ALL THE TIME. I can't understand how you've never
come across it.

> The
> only thing that annoys me about forward declarations is that some people
> insist on putting a list of them at the start of their files, regardless
> of their need - such lists can get inconsistent and are a maintenance
> irritation.

This is what the proposal will help eliminate. For local declarations
anyway. For exported, shared functions, it would need a much bigger
change to eliminate having to declare functions in headers.

--
bartc

David Brown

unread,
Jul 27, 2017, 8:02:08 AM7/27/17
to
On 27/07/17 12:07, bartc wrote:
> On 27/07/2017 08:29, David Brown wrote:
>
>> At first glance, I think it is likely that forward declarations could be
>> made redundant - though I certainly have not given it serious thought.
>> Basically, the compiler could first read through the file and whenever
>> it finds a function definition, class definition, struct definition,
>> etc., it could construct an appropriate forward declaration. Then it
>> could artificially insert these into the code and compile as normal.
>
> It wouldn't need to be that crude. That might be what a separate tool
> would do to transform such C code into conventional C. (Actually,
> exactly what I used once, which identified local and export functions
> given stylised function definitions, and wrote out .cl and .cx header
> files respectively.)
>

Certainly it can be done that way. There is the "cproto" program that
does a fair amount of that already, which I believe was designed for
automating the generation of function prototypes from old C90 and K&R C
for use in C99. A similar idea could be used here, with the benefit
that you don't need to change the C (or C++) compiler at all, nor the
standards.

>> It would be more of an inconvenience, I think, for other tools that
>> parse code in a simpler way, such as highlighting editors.
>
> This is not parsing, which stays the same.
>
> If it wants to colour different kinds of identifiers in different ways,
> then yes it might need to look ahead in the file, but it is not exactly
> a trivial task anyway as it needs to resolve variables, typedefs,
> macros, enum names, and labels as well as function names. (How does such
> an editor manage with C++?)
>

No, I agree it is not a trivial task - so it is not helpful to make it
harder!

>> I suppose it all depends on your style of coding, but personally I
>> rarely need forward declarations - so they are no bother to me.
>
> I think everyone does unless they pay attention to the exact ordering of
> functions in a file.
>
> You're writing function F, and it calls G. Now you have to write G, but
> you have to make sure it precedes F (so you can no longer read your code
> top-down).

Very roughly, you can do "top down" coding (write F first, then write G)
or "bottom up" coding (write G first, then write F). If you put the
definition of G earlier in the source than the definition of F, then you
don't need forward declarations and your code /does/ read top-down if
you think of "bottom up" coding. And it means that if you want to find
the definition of a function you are using, you only need to look in one
direction - up the file.

That is not the way everyone likes to arrange their code in a file, but
it is a perfectly valid, logical, consistent and readable way to do it.

Modern editors and IDE (by "modern", I mean "this century") have no
problem with multiple windows on the same file, showing "table of
contents" or "outlines" of functions, jumping to definitions or
declarations of functions, etc.

>
> You now modify F and it calls a new function H, and H is inserted
> between G and F.
>
> Later, you modify G to call H too. But now that won't work, because G
> won't see H. You have to now move H to just before G, or create (and
> have to maintain) a forward declaration of H.
>

First, if you have a call graph where F calls G, and both F and G call
H, you probably have a poor structure in your code. The exception would
be when H is a more general utility-type function - and you would know
that when writing H, and thus place it earlier in the code in the first
place.

Second, cut and paste to move H is a few seconds work - it is less
effort than writing a forward declaration (even though that would not be
a significant effort either).

> You can try inserting every new function at the top of the file, but
> then, such a function may need to call an existing function, so that
> won't work.

Just write your functions in a sensible order. Sometimes that means
writing code that uses functions before they are defined, sometimes that
means moving about a bit in the file before writing a new function.

You are imagining problems - unless somehow I am unique in the way I
write code. It is rare that I ever have to move a function definition
around in code to get the order write, and rarer still that I ever need
to make forward declarations for my static functions (all non-static
functions have extern declarations in a matching header file).

>
> Or, you write function F which calls G which then calls F; where does
> each go?

In the bin. Circular dependencies are almost always a terrible way to
structure your code. And for my type of work, recursion of any sort
should be met with extreme scepticism - stack space is limited,
reliability is paramount, and you have to be /very/ sure of /hard/ upper
limits for the recursion depths.

More generally, of course, this is an occasions where a forward function
declaration is necessary.

>
> This stuff happens ALL THE TIME. I can't understand how you've never
> come across it.

No, it does not happen all the time - at least not when you have a plan
of the code you are writing.

>
>> The
>> only thing that annoys me about forward declarations is that some people
>> insist on putting a list of them at the start of their files, regardless
>> of their need - such lists can get inconsistent and are a maintenance
>> irritation.
>
> This is what the proposal will help eliminate. For local declarations
> anyway. For exported, shared functions, it would need a much bigger
> change to eliminate having to declare functions in headers.
>

I eliminate these lists of static forward declarations by not having
them. Problem solved.


bartc

unread,
Jul 27, 2017, 8:23:42 AM7/27/17
to
On 27/07/2017 13:01, David Brown wrote:
> On 27/07/17 12:07, bartc wrote:

>> I think everyone does unless they pay attention to the exact ordering of
>> functions in a file.
>>
>> You're writing function F, and it calls G. Now you have to write G, but
>> you have to make sure it precedes F (so you can no longer read your code
>> top-down).
>
> Very roughly, you can do "top down" coding (write F first, then write G)
> or "bottom up" coding (write G first, then write F). If you put the
> definition of G earlier in the source than the definition of F, then you
> don't need forward declarations and your code /does/ read top-down if
> you think of "bottom up" coding. And it means that if you want to find
> the definition of a function you are using, you only need to look in one
> direction - up the file.

OK, so you have to worry about the ordering of functions in a file.
(I've just grabbed the first source file to hand, and counted 92 functions.)

> First, if you have a call graph where F calls G, and both F and G call
> H, you probably have a poor structure in your code. The exception would
> be when H is a more general utility-type function - and you would know
> that when writing H, and thus place it earlier in the code in the first
> place.
>
> Second, cut and paste to move H is a few seconds work - it is less
> effort than writing a forward declaration (even though that would not be
> a significant effort either).

So you have to think carefully about the ordering of functions in a
file. And at maintaining that order.

>> You can try inserting every new function at the top of the file, but
>> then, such a function may need to call an existing function, so that
>> won't work.
>
> Just write your functions in a sensible order.

So you have think carefully ... etc

>> Or, you write function F which calls G which then calls F; where does
>> each go?
>
> In the bin. Circular dependencies are almost always a terrible way to
> structure your code. And for my type of work, recursion of any sort
> should be met with extreme scepticism - stack space is limited,

With my type of work, there is a lot of recursion (not just in languages
but with any kind hierarchical data structure).

> More generally, of course, this is an occasions where a forward function
> declaration is necessary.

So now you have to have declarations.
>
>>
>> This stuff happens ALL THE TIME. I can't understand how you've never
>> come across it.
>
> No, it does not happen all the time - at least not when you have a plan
> of the code you are writing.

So you have to plan the layout, which means thinking carefully etc

> I eliminate these lists of static forward declarations by not having
> them. Problem solved.

Sorry, it isn't. You're 'solving' the problem by worrying about things
and doing a bunch of work that would otherwise not be necessary.

The proposal would do away with that leaving you free to concentrate on
other things.

--
bartc

David Brown

unread,
Jul 27, 2017, 9:07:26 AM7/27/17
to
On 27/07/17 14:23, bartc wrote:
> On 27/07/2017 13:01, David Brown wrote:
>> On 27/07/17 12:07, bartc wrote:
>
>>> I think everyone does unless they pay attention to the exact ordering of
>>> functions in a file.
>>>
>>> You're writing function F, and it calls G. Now you have to write G, but
>>> you have to make sure it precedes F (so you can no longer read your code
>>> top-down).
>>
>> Very roughly, you can do "top down" coding (write F first, then write G)
>> or "bottom up" coding (write G first, then write F). If you put the
>> definition of G earlier in the source than the definition of F, then you
>> don't need forward declarations and your code /does/ read top-down if
>> you think of "bottom up" coding. And it means that if you want to find
>> the definition of a function you are using, you only need to look in one
>> direction - up the file.
>
> OK, so you have to worry about the ordering of functions in a file.
> (I've just grabbed the first source file to hand, and counted 92
> functions.)

I don't worry about the order of functions - I can write code in an
order that suits me without worrying. It is hard to tell, since I have
written my C code this way for decades, but I don't believe it is a
difficult habit to learn.

And 92 functions in one file is, IMHO, a good deal too many.

>
>> First, if you have a call graph where F calls G, and both F and G call
>> H, you probably have a poor structure in your code. The exception would
>> be when H is a more general utility-type function - and you would know
>> that when writing H, and thus place it earlier in the code in the first
>> place.
>>
>> Second, cut and paste to move H is a few seconds work - it is less
>> effort than writing a forward declaration (even though that would not be
>> a significant effort either).
>
> So you have to think carefully about the ordering of functions in a
> file. And at maintaining that order.
>

As I say, I don't have to think about it. And I don't have to "maintain
the order" - my functions do not wander about inside their files when I
am not looking. It is rare that I ever have to change the order of
functions within a file - usually that will only happen when doing some
major restructuring, in which case a bit of cut-and-paste is a
negligible detail in the work.

>>> You can try inserting every new function at the top of the file, but
>>> then, such a function may need to call an existing function, so that
>>> won't work.
>>
>> Just write your functions in a sensible order.
>
> So you have think carefully ... etc
>

No - it does not take significant thought. It is really very, very simple.

>>> Or, you write function F which calls G which then calls F; where does
>>> each go?
>>
>> In the bin. Circular dependencies are almost always a terrible way to
>> structure your code. And for my type of work, recursion of any sort
>> should be met with extreme scepticism - stack space is limited,
>
> With my type of work, there is a lot of recursion (not just in languages
> but with any kind hierarchical data structure).
>
>> More generally, of course, this is an occasions where a forward function
>> declaration is necessary.
>
> So now you have to have declarations.

Yes. I have not suggested, at any time, that you don't sometimes need
forward declarations. I have only said that I very rarely need them
(excluding, of course, declarations in a header for exported functions).
If you are using recursion, you will need forward declarations on
occasion. (The same applies to types - for most types, you do not need
any kind of forward declarations. But for recursive structures, you do.)


>>
>>>
>>> This stuff happens ALL THE TIME. I can't understand how you've never
>>> come across it.
>>
>> No, it does not happen all the time - at least not when you have a plan
>> of the code you are writing.
>
> So you have to plan the layout, which means thinking carefully etc
>

When I start writing code, I have a pretty good idea of the basic
structure of my code - the functions I will need, and which ones will
call others. Then I know the order they will go in the file. I may or
may not write them in that order - that will depend on the kind of code
I am writing, how much testing I will be doing underway, etc.

>> I eliminate these lists of static forward declarations by not having
>> them. Problem solved.
>
> Sorry, it isn't. You're 'solving' the problem by worrying about things
> and doing a bunch of work that would otherwise not be necessary.
>

As I said, ordering the code as I do does not involve work or effort,
and certainly not worry. You are imagining a problem that does not
exist - simply because it means doing something in a way that is
different from your own habits.

> The proposal would do away with that leaving you free to concentrate on
> other things.
>

It would change /nothing/ for me.

Robert Wessel

unread,
Jul 27, 2017, 12:57:53 PM7/27/17
to
While I have no real objection to making forward declarations option
in C, and it's certainly been done in many other languages, I've not
really thought about it enough to consider if there are any hidden
pitfalls (one of the big ones would have been the implicit definitions
which are no longer allowed). But you could almost certainly make
such a thing work for the vast majority of functions, and so long as
the language were defined in such a way that the compiler can diagnose
any remaining cases.

OTOH, while this might be a nice enhancement, it's a pretty small one
in terms of usability as far as I'm concerned. My list of things I
want improved in C (and C++) has a bunch of stuff I'd rate as having
much higher importance/significance than this change. So while I'd
not really object on any technical grounds, I'd object on the grounds
of this being an inappropriate priority. OTTH, the C committee really
doesn't pay much attention to my objections...

Vir Campestris

unread,
Jul 27, 2017, 3:57:37 PM7/27/17
to
On 27/07/2017 13:01, David Brown wrote:
<snip>
> Second, cut and paste to move H is a few seconds work - it is less
> effort than writing a forward declaration (even though that would not be
> a significant effort either).
</snip>

You must have a very clever source control system.

I've never seen one that will distinguish "This lump of code has been
moved" from "This lump has been inserted, and that one deleted".

Which becomes really interesting in reviews, when you really need to
know whether it has been changed slightly when it moved.

Andy

Rick C. Hodgin

unread,
Jul 27, 2017, 4:18:31 PM7/27/17
to
From a comment Linus Torvalds made during this presentation on Git:

2007 - Google Tech Talk: Linus Torvalds on git
https://www.youtube.com/watch?v=4XpnKHJAok8

He said the ability exists within the git history to track movement
and editing of lines of code from their current location back to
their original location, even if they've moved from file to file.

He indicated it would be an expensive operation, and it would likely
involve writing some custom code to examine the evolution of blocks
over time, but he indicated it is possible with Git.

It does not appear to be something that's done during normal commit
cycles, however. IIRC, Git can identify that file x was renamed to
file y, even if it also has some changes within it.

Paavo Helde

unread,
Jul 27, 2017, 4:53:59 PM7/27/17
to
If your ability to refactor code starts to become limited because of
source control and code review issues then you know you are in a big
trouble! Cart before horse and all that stuff...


David Brown

unread,
Jul 28, 2017, 3:21:09 AM7/28/17
to
Again, this is /not/ a problem - because it does not happen often.

And the period of the development process when you might be likely to be
moving bits around more, is the time when you are writing a lot of code
and making a lot of changes anyway.

I do accept, however, that moving code can make it harder to see changes
in the source when comparing versions - it is a valid argument against it.


Ian Collins

unread,
Jul 28, 2017, 4:48:43 AM7/28/17
to
On 07/27/17 07:42 AM, Rick C. Hodgin wrote:
> This is the year 2017. Computers are powerful, and advanced and have
> algorithms for all kinds of compiler needs developed. The time of any
> component of a modern compiler REQUIRING forward declarations is long
> since past, save the needs of legacy software that was written for a
> system with that expectation.
>
> -----
> What can be done to initiate a grass roots movement to remove the need
> for having forward declarations in upcoming C and C++ Standards?

Such a change would be largely irrelevant in C++ where most functions
are class members which are declared in class declarations. The reset
tend to be anonymous namespace functions which every coding standard
I've worked to live at the top of the compilation unit.

> I think some kind of compiler switch which disables the forward-
> declaration requirement, allowing an additional pass to be run on
> source code to resolve unknown references would be desirable.

C++ name lookup rules are complicated enough without adding more
complexity...

--
Ian

Bo Persson

unread,
Jul 28, 2017, 5:43:59 AM7/28/17
to
On 2017-07-28 10:48, Ian Collins wrote:
> On 07/27/17 07:42 AM, Rick C. Hodgin wrote:
>> This is the year 2017. Computers are powerful, and advanced and have
>> algorithms for all kinds of compiler needs developed. The time of any
>> component of a modern compiler REQUIRING forward declarations is long
>> since past, save the needs of legacy software that was written for a
>> system with that expectation.
>>
>> -----
>> What can be done to initiate a grass roots movement to remove the need
>> for having forward declarations in upcoming C and C++ Standards?
>
> Such a change would be largely irrelevant in C++ where most functions
> are class members which are declared in class declarations. The reset
> tend to be anonymous namespace functions which every coding standard
> I've worked to live at the top of the compilation unit.
>

And in C++ you can already abuse the rule than class members need not be
forward declared:

struct program
{
// all functions go here
};

The "member functions" can now freely call each other irrespective of
their declaration order.


Bo Persson

Rick C. Hodgin

unread,
Jul 28, 2017, 7:49:11 AM7/28/17
to
On 7/28/2017 4:48 AM, Ian Collins wrote:
> On 07/27/17 07:42 AM, Rick C. Hodgin wrote:
>> This is the year 2017. Computers are powerful, and advanced and have
>> algorithms for all kinds of compiler needs developed. The time of any
>> component of a modern compiler REQUIRING forward declarations is long
>> since past, save the needs of legacy software that was written for a
>> system with that expectation.
>>
>> -----
>> What can be done to initiate a grass roots movement to remove the need
>> for having forward declarations in upcoming C and C++ Standards?
>
> Such a change would be largely irrelevant in C++ where most functions
> are class members which are declared in class declarations. The reset
> tend to be anonymous namespace functions which every coding standard
> I've worked to live at the top of the compilation unit.

What about the case where file1.h and file1.cpp exist, and they
possess their own functions and do their own thing autonomously.
And then file2.h and file2.cpp exist, and they do likewise. But
then later you decide you want to implement some features in file1
which reference file2 abilities, and features in file2 which also
reference file1 abilities.

If you only declare their references in the .h files and write the
bode code in the .cpp file then it works, but if you want something
like an accessor and want to code the entire function in the .h
file you cannot do it because in either the file1-to-file2, or the
file2-to-file1 reference, something will be undefined if you're
only using the file1.h and file2.h headers. You have to now create
something like a common.h header which includes those things file1
and file2 will share so you can include common.h ahead of both of
them, then all works.

And as you make your file1 and file2 work also with file3 and
file4 and fileN, then you begin to have this convoluted requirement
of making sure things are defined before their use, when they are
simply defined already a few lines further down. It seems to be
a legacy exercise in ridiculousness when computers today are more
than capable enough to perform the extra pass for us, saving us
the labor time and headaches of making things just right for the
compiler's needs. I prefer to place value ahead of the compiler,
and make the developer's needs paramount when the compiler is
capable of performing a task for us.

In my view, the existing system works well for pointer references,
but not for member references. At least that's been my experience.
I could be doing it wrong.

Rick C. Hodgin

unread,
Jul 28, 2017, 7:53:48 AM7/28/17
to
I've never known this. Do you know if something like this works
properly?

struct program
{
#include "file1.h"
#include "file2.h"
#include "file1.cpp"
#include "file2.cpp"
};

And in that way, then file1.h can reference member functions
defined in file2.h and given a body in file2.cpp?

If so, that might cure all of my woes. :-)

> The "member functions" can now freely call each other irrespective of
> their declaration order.

Awesome. Thank you.

Yours in software,
Rick C. Hodgin

David Brown

unread,
Jul 28, 2017, 10:15:12 AM7/28/17
to
That might work, I think, as long as there are no conflicts between the
files (like types, functions, etc., with the same name in both file1 and
file2). I believe that in theory, it is not valid to include standard
headers at any scope other than file scope - but in practice I expect it
would work.

Of course, main() would no longer be the start of the code - you'd need
to add something like:

int main() {
program prog;
return prog.main();
}

outside of the "struct program".

(If you have a lot of data, you might want to put "program prog" outside
of main so that it goes in the bss section rather than on the stack.)


Give it a shot, and see if it works for you.

Rick C. Hodgin

unread,
Jul 28, 2017, 2:35:01 PM7/28/17
to
I was able to test this program in Visual Studio 2015 and it worked.
I was able to reference class xyz and its members before it was /
they were defined:

-----[ Begin ]-----

#include <stdlib.h>
#include <stdio.h>

struct STest
{
int a;

// Here's a reference to STest::xyz before it's defined
int STest_main(int argc, char* argv[])
{
STest::xyz* x = new STest::xyz();

x->m_int = 5;
x->printf("something");

return 0;
}

class xyz
{
public:
xyz() {};
~xyz() {};

void printf(char* text) { ::printf(text); }

public:
int m_int;
};

int b;
};

int main(int argc, char* argv[])
{
STest t;

t.STest_main(argc, argv);
return 0;
}

-----[ End ]-----

Rick C. Hodgin

unread,
Jul 28, 2017, 2:40:51 PM7/28/17
to
On 7/28/2017 2:34 PM, Rick C. Hodgin wrote:
> -----[ Begin ]-----
>
> #include <stdlib.h>
> #include <stdio.h>
>
> struct STest
> {
> int a;
>
> // Here's a reference to STest::xyz before it's defined
> int STest_main(int argc, char* argv[])
> {
> STest::xyz* x = new STest::xyz();

// In my haste at refactoring, I also forgot these other references,
// both of which work with a defined before, and b defined after.

a = 3;
b = 4;

> x->m_int = 5;
> x->printf("something");
>
> return 0;
> }
>
> class xyz
> {
> public:
> xyz() {};
> ~xyz() {};
>
> void printf(char* text) { ::printf(text); }
>
> public:
> int m_int;
> };
>
> int b;
> };
>
> int main(int argc, char* argv[])
> {
> STest t;
>
> t.STest_main(argc, argv);
> return 0;
> }
>
> -----[ End ]-----

I think I may have found a reason to withdraw my earlier request
to have this non-forward declaration feature added to C/C++. It
already exists! (at least to some extent)

Juha Nieminen

unread,
Jul 31, 2017, 6:42:06 AM7/31/17
to
In comp.lang.c++ Rick C. Hodgin <rick.c...@gmail.com> wrote:
> I think some kind of compiler switch which disables the forward-
> declaration requirement, allowing an additional pass to be run on
> source code to resolve unknown references would be desirable.

You can compile a compilation unit into an object file, a statically
linked file, or a dynamically linked file.

Even when compiling simply to an object file, the compiler might not,
at that point, have any access to the definition of a function in some
other source of object file. It's only at linking time that all the object
files come together.

How exactly is the compiler supposed to create the object file when it
can't see the function being called? This requires more than just a
function pointer to be set later. The parameters need to be put onto
the stack. The compiler can't know, without seeing the function
declaration, how it should put them there (eg. if you give an
int as parameter, but the function takes a double, the compiler
needs to do a conversion; it can't do that if it can't see that the
function is taking a double).

It becomes even more complicated with dynamically linked libraries.
Those may not be available at compile or even link time at all,
only at run time.

bartc

unread,
Jul 31, 2017, 6:57:07 AM7/31/17
to
I think you're posting at cross-purposes.

As I understand it, the proposal is about relaxing requirements for
forward declarations of functions in the /same/ translation unit.

Not for eliminating declarations of functions in other modules (ie.
pretty much doing away with header files). As those wouldn't be
/forward/ declarations (more sideways ones).

So it means being able to write this:

-----------------------------
int main(void) { fn(10,20);}
void fn(float a,int b) {}
-----------------------------

instead of:

-----------------------------
void fn(float,int); // forward declaration of fn
int main(void) { fn(10,20);}
void fn(float a,int b) {}
-----------------------------

or:

-----------------------------
void fn(float a,int b) {} // re-ordering functions
int main(void) { fn(10,20);}
-----------------------------

--
bartc




Rick C. Hodgin

unread,
Jul 31, 2017, 8:34:04 AM7/31/17
to
I do not advocate forward-declarations that are unknown across
object files, but only within a single compilation.

In many cases doing this will fail:

#include "file1.h"
#include "file2.h"

...because there are dependencies in file1.h which require the
information that's declared in file2.h. You must order them as:

#include "file2.h"
#include "file1.h"

But what can also happen is file1.h and file2.h both have some
dependencies on each other, so that if any members are referenced
the compilation will fail.

My goal in removing the requirement of having forward-declaration
is to resolve this issue so that something needs only be defined
somewhere in the compilation, and not before it's first referenced.

Many other languages have done away with the forward-declaration
requirement. It seems to be a proper thing for a compiler running
on modern hardware in 2017.

There's nothing to prevent a compiler from NOT implementing the
relaxation, and to maintain things as they are. In fact, I think
it would be essential for this relaxation to be only a feature
that can be turned on, and not a default feature.
0 new messages