All About "Include" By Bruce Johnson and Mark Goldberg
- Wednesday, 16 March 2011 02:59
- Last Updated on Wednesday, 16 March 2011 03:15
why would an include be parsed twice? That has to do withthe way includes are used.
for example an inc file can contain other includes.
So say browse.inc includes file.inc and view.inc includes file.inc and a window includes both browse.inc and view.inc, then the files.inc is included twice.
One solution is to always store "names" and just filter out the seocnd occurance. Another is to "explicitly" tell the system you want to exclude duplciates (hence ,ONCE).
However Include is not just for .Inc files. You can Include CLW code as well, (or indeed anything else) so to automatically remove duplicates would break that.
In the early days of Clarion there was no ONCE, so there's an ugly hack in the INC file which wraps the whole file in a conditional compile. This is a technique used in C a fair bit as well.
Had we had ONCE from the beginning then we'd have the best of both worlds - the ability to inlcude a code snippet (or something else) multiple times in the same scope, and a way to single out .INC files for special "only include this once" behaviour.
But by then the hack had already taken hold, so now both approaches are used.
OK, as Bruce pointed out, files can easily be included multiple times and there needs to be a mechanism in place to avoid that process, otherwise you'll have duplicate labels.
Newer languages have little if any need for includes
Among the older languages (like CW), nearly all of them have an IFDEF / IFNDEF compiler directive approach. CW Doesn't have that. The closest you can get, it to use a conditional OMIT/COMPILE, and add an extra equate(1) to drive that conitional.
IF Once were applied INSIDE of the included file, then it would make sense, and quite frankly that's what an IFNDEF does.
This topic is NOT connected to ABC, other than the fact that ABC uses classes, which in the CW world calls for INC/CLW
Q: OK, WHY do we have INC/CLW ?
A: We need to expose the contents of the .INC to two places
and the contents of the .CLW to one only
INCLUDE()'s are perfect for situations where the identical code needs to appear in more than one place.
So what does the following do?
Well, stop and think about just INCLUDE('SomeEquates.clw')
Q: What does that do?
A: It's as if you had copied/pasted those lines at the spot where the INCLUDE appears
OK, so what's going on with classes then?
well the CLASS,TYPE and often some equates, and other things like QUEUE,TYPE need to be exposed to larger scope, so they're put in the .INC
OTOH the details of the class, the MyClass.CLW, are kept seperate.
It's just a module that is compiled (the project languge uses the command [link] to compile a module. So at the CW language level they added an attribute to CLASS the ,LINK('modulename'[, conditional])
So, at the lowest level (either a base DLL), or up in the EXE (when the EXE is stand alone) you'll LINK in (compile) that module.
OK, Mark - you said you often need the contents of the .INC in two places.
Right, well the MyClass.CLW is often written with an empty MEMBER() statement, which means that it's a blank slate. It inherits NOTHIN', zip, zero, nada. So little in fact, that it doesn't even know about the contents of MyClass.INC soooo.... you wind up adding an INCLUDE('MyClass.INC') near the top of MyClass.CLW
FWIW, that zip zero nada, is so complete that the module is unaware of RTL commands, UNLESS you do do this
However, CW really does that for you automagically by just saying
If you don't believe me... add a bug to builtins.clw and watch the compiler fail on this program
Also Win32.LIB is automagically LINKed in
Which is why *some* API calls don't need a .LIB to be linked in to call them.
Its also a pain when Win32.LIB changes, and leads to duplicates at link time.
If you're using C6+
Add this line to a .INC file
Put one outside of the OMIT and another inside of it.
PRAGMA('project(#message "----------------top of ctStrings.inc")')
PRAGMA('project(#message "----------------test from ctString.inc in OMIT implies _ctStringsLinkMode_ false ")')
PRAGMA('project(#message "------- --------test from ctString.inc in COMPILE implies _ctStringsLinkMode_ true")')
For fun, add a project setting -> define
this will force **EVERTHING** to recompile
FWIW, that approach will show a difference between an include the soley relies on the conditional OMIT, and one that uses ,ONCE