While we've crossed wires a bit, I'll reply all the same :-)
At 10:27 PM +0100 28/2/03, Frank Heckenbach wrote:
Grant Jacobs wrote:
./GHJ_AARegions.pas:49: type name expected, identifier `Fnames' given ./GHJ_AARegions.pas:49: warning: missing type in declaration of `Infname' ./GHJ_AARegions.pas:54: warning: parameter has incomplete type
My trouble was fnames *is* a type. It is *only* defined as a type. So how the heck does the compiler come away thinking that its an identifier?????
Surely it is an identifier. In Pascal, an identifier is any sequence of letters, numbers and underscores (subject to the syntactic restrictions) which isn't a keyword. So any type name is also an identifier.
Ah, I get it. Slow on the uptake... This ought to be re-worded (if you can stand me!), e.g.
type name expected: unknown identifier 'Fnames' given ^^^^^^^
Sounds silly, but I read the original message to mean "the identifier fnames was given but it doesn't fit here" (but it *does* fit there, so I got confused naturally enough!), rather than "I'm expecting a type identifier; I have no idea what fnames is". I should know by now to read all error messages as "you goofed; I have no idea what you're up to, here's my next-to-useless guess" ;-) Sorry, couldn't resist.
You want to distinguish known and unknown identifiers in the error messages to make things clearer (?)
Since these uses statements were within the interface section, I presumed the definitions would propagate upwards so that they form a hierarchy. Or, put another way, I assumed the interface of a unit is extended by any units it uses in its interface section.
As you found out, this isn't the case.
This is not how MW Pascal does it if my memory is right (and it has been a while since I played with that...). And left like this I can't see how you can properly inherit interfaces. (I don't have time to dredge around the standards, sorry, so I'm going on common-sense.)
{=>} points out the offending line of source. If this is truly the problem, then I presume there is no way of building a hierarchy of units in GPC at present? (In this case my safest strategy is to have every unit uses *all* the lower units directly, "just in case".
Yes, in a situation where each unit builds on all the previous ones, that's usually what one does.
Not necessarily: its what you do if you have no other choice!! :-) It forces all higher units to know the dependencies of the lower ones because you can't inherit the dependencies.
Then again, there are other situations. E.g., you might have some utility units (such as some of those distributed with GPC, say StringUtils, FileUtils, RegEx, ...) which are used where they're needed; you might have some general low-level units which are used in every unit of your project; you might have some "main functionality" units which build upon each other (i.e., a basic version of something, a refined or extended version etc., or some other functionality which uses the first one); and you might have some that are parallel (different functionalities which do not require each other) which are only put together in the main program or a highest-level unit ...
I think it depends on the situation what one needs. If the compiler would automatically re-export everything imported, you'd have less choices to structure your project.
Unless you compare units/modules and just consider that they just work from opposite views about how to restrict what is exported:
In units:
When uses is placed into an interface, all of the interface of used unit is propagated (inherited, etc.) unless the programmer restricts what is imported in the uses. [This is what I was hoping for, that is.]
In modules:
Nothing from a uses placed in an interface is exported (propagated, etc.) unless it is explicitly exported.
And in either case interfaces imported into implementation sections are hidden.
Modules are more explicit (and more pendantic!), but you also have to effectively state everything twice, once in a export statement and once just in the interface. If you have a lot to export, this must get to be a handful.
Units are more permissive unless explicitly restricted by just importing specific parts of an interface.
Once you have a means of obtaining just a specified portion of an interface, the module and unit approaches presented here would be equivalent (AFAICS), just coming from different angles. If you also added an 'export all' of a sub module (which I think you were mentioning the other day), they'd pretty much be exact alternatives. (Export is still in the docs as 'not yet implemented!)
Think of the unit mechanism presented here as being akin to inheritance in class libraries. Code that uses a class doesn't have to explicitly import all dependencies: they just import the class and get all the dependencies "free". (That said, unless they use introspection in some way, they still need to know the names of the subclasses, etc., but we're (or rather, I'm) getting off topic...!)
Yes, I could convert them all to classes, but not on the initial port... first time around I want to keep things as close to how they are. Perhaps I'll just have to re-convert everything to modules.
And as I said, I thought this was how MW Pascal units did things. Anyone know how Delphi/Kylix goes about this? (My 'Deplhi in a Nutshell' isn't helpful here and I haven't time to test this just yet.)
Or put, another way, I might just as well use includes to make everything one big flat program. Sorry, but I *am* frustrated!)
This would have the disadvantage that separate compilation (automake) wouldn't be possible ...
I know! -- I'm getting frustrated enough that I might just have to do this... (I don't *want* to...) Modern computers are fast enough speed won't be an issue, but re-use of the units eventually will. I'm just trying to get the initial port going at all first!
- This is the correct behaviour?: surely I should be able to use a
higher-level module and have all the lower-level modules definitions within that higher-level module "gotten" at the same time without have to explicitly duck behind the scenes and drag out each module??? Excuse me for asking this, but its not terribly clear from the docs, at least on my reading of it.
I'm not sure if the GPC docs mention it (as usual, they're quite incomplete), but both BP (for units) and EP (for modules) are quite clean about it. EP allows for re-exporting imported identifiers, but they have to be mentioned explicitly in the `export' clause.
See above. So BP can't inherit subunits and you have to explicitly pick up dependent units?
Long time ago, there was a short discussion about re-exporting everything from an imported unit -- not automatically, but with some explicit directive ("unit inheritance"), but AFAIK, this hasn't been pursued further yet ...
See above.
Addendum: I've since seen section 6.1.8.2. The source structure of UCSD/Borland units of the docs say "A units exports everything declared in the interface section". This it doesn't appear to do if we consider things in the units imported via uses.
Importing <> declaring. The things are declared in the interface section of the lower-level units, but not in the one of the present unit.
This could be confusing and/or limiting: consider this case:
unit FileOps;
interface uses FnameUnit;
function WordCount( var fname: fnames ): integer ;
implementation { expected stuff... } end.
(Leave aside the fact most people would pass the opened file, not its name!) Assume fnames is defined in FnameUnit. Naturally, we want fnames exported for users of unit FileOps. Under the 'no export' scheme the other units need to "just know" that unit FnameUnit has the definition required and import FnameUnit when using FileOps. Under the alternative scheme other units can just 'uses FileOps' and get everything they need without have to know about any dependencies. The latter has its advantages... It'd be nicer if we had the option of only passing on just the things needed by FileOps should we want to, e.g. uses FnameUnit only ( fnames ); (in analogous fashion to how import specifies subsets.)
(I hope I'm not wasting your time with all this -- I like exploring these issues for that one day I get around to developing my own programming language... :-) )
[snip]
In fact, quite a bit of work in GPC is currently spent on continuing after an error within one source file. This is extra work in the parser (syntactic recovery, still far from perfect) and in the rest of the compiler (passing around error indicators (`error_mark_node') and trapping them in the right places to avoid crashing).
OK, it was only a thought. You've a point about extra overhead for error recovery/tracking across files.
I'm wondering if it wouldn't be easier to drop this all. Today's compilation times are usually short enough that one can retry after each error. But then, the current behaviour is GCC compatible, so I guess we'll have to keep it ...
One day, maybe... :-)
For a similar reason, having a brute force compile-all option appeals to me (do the equivalent of --automake, but simply recompile all units you run into regardless of what status the units have [except that you'll want to detect circular dependencies!]). I'm assuming this would avoid any issues in automake, but of course I could be wrong since I don't know how automake is implemented. I'd prefer the little time "wasted" by the computer re-compiling everything, to me having to manually do things.
Now to try figure out how GPC claims a type-mismatch on something that is definitely the same type and the type is only defined in one place...
I don't see it claiming a type-mismatch. It speaks of a "missing type" etc. That's one of those follow-up errors I mentioned (not exactly wrong, but somewhat redundant). Certainly, we could add some more code to avoid this particular message (and dozens of other similar situations). Usually I'm happy if it doesn't crash in such situations ...
:-)
Same issue as before, it seems. If something is unknown, state so explicitly...?
As a general rule, everything after the first error message may or may not be accurate. This will always remain true, since no compiler can guess what you really mean when there is an error.
Like most people, I've been through that particular mill for a long time...! (But I'm still capable of confusing myself over an error message!) We'd all love a compiler that didn't do this, but "that'll be the day..." :-) (Maybe in my own programming language...;-) )
[snip]
Grant