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.