Weird type/identifier conflicts

Grant Jacobs gjacobs at bioinfotools.com
Sat Mar 1 00:48:23 CET 2003


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!

>  > 1. 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
-- 
-------------------------------------------------------------------
Grant Jacobs Ph.D.                                     BioinfoTools
ph. +64 3 476 1820  (office, after 10am)               PO Box 6129,
or  +64 25 601 5917 (mobile)                               Dunedin,
gjacobs at bioinfotools.com                               NEW ZEALAND.
    Bioinformatics tools: deriving knowledge from biological data
Bioinformatics tools - software development - consulting - training
Check out the website for more details: http://www.bioinfotools.com

The information contained in this mail message is  confidential and
may  be legally privileged. Readers of this message who are not the
intended recipient are hereby notified that any use, dissemination, 
distribution or reproduction of this message is prohibited. If  you
have received this message in error please notify the sender immed-
iately and destroy the original message.  This applies also to  any
attached documents.




More information about the Gpc mailing list