include

When you write a large program it is often helpful to break it up into logically separate files, by using include statements. Sometimes you will want to reuse some code that you have previously written, or that someone else has written. Rather than copy this code into your main program, you can use an include statement to refer to the file containing the code. The format of the include statement is:

include <filename> [as <namespace_identifier> ]

This reads in (compiles) a phix source file.

Any global symbols that have already been defined will be visible in the included file.

N.B. Only those symbols defined as global in the included file will be visible (accessible) in the remainder of the program.

An included file can include other files. In fact, you can "nest" included files to any depth.

The filename may be absolute (full directory path) or relative. For the latter, phix maintains a table of active directories to locate it (see note[1] below). This allows, for example, a "stub" file in demo\arwendemo, named "arwen.ew", which contains say
    include ..\arwen\arwen.ew
and when the compiler is processing that file it can use the "..\\arwen" part (or an absolute directory) to locate any sub-includes such as misc_arwen.ew. Of course you do not have to use a stub file, other apps could equally specify the absolute/relative directory part, but it allows all other programs in demo\arwendemo to just use "arwen.ew", and if one day I decide to reorganise the directories, or perhaps have several different versions that I want to switch between, only one file needs to be edited. You are perfectly free to "nest" any "stub" files if that helps. When the compiler reaches EOF of "..\\arwen\\arwen.ew", it clears a flag against the "..\\arwen" to prevent subsequent include statements looking there, unless of course a later include statement (temporarily) re-activates/re-specifies it.

This relative directory handling lets you organize your include files according to application areas, rather than lumping them all into one central directory.

Include file names typically end in .e, or sometimes .ew or .eu (when they are intended for use with Windows or Linux). This is just a convention. It is not required.

An include statement will be quietly ignored if the file has already been included[2], except for any optional namespace, which becomes available for subsequent use whether or not the file has previously been included.

If a namespace identifier is specified it declares a local identifier that can be used to explicitly qualify global symbols in the specific included file that you want to use in the main file. This can be used to disambiguate references to those symbols, or simply to promote clarity.

However I feel I must say that namespaces are NOT an excuse for gratuitous ambiguity.
The names of global routines should be meaningful in their own right.
Namespaces should be considered an escape strategy rather than a design philosophy.
It is not cool for there to be 38 routines called "new()".
It is not clever to make someone think the code is calling a standard routine.
It is not smart to force the use of namespaces when you may as well make the qualifier part of the global name.
Instead of, for instance, date:format() and time:format() it is much better to have date_format() and time_format() - the code will be easier to follow, there will be no cases where an unqualified format() for whatever reason invokes the wrong one, the compiler will make fewer complaints, and the help lookup system will almost certainly work better.

See also Scope Rules and note[3] below.

An include statement must be written on a line by itself. Only a comment can appear after it on the same line.

The compiler knows enough about most files in the builtins directory to include them automatically as required.

Everything in builtins\VM is an autoinclude except for pFEH.e, optable.e, and pMemChk.e, which are really part of p.exw. There is no need to worry about or remember the names of any of: pApnd.e, pcallfunc.e, pcfunc.e, pcmdlnN.e, pDeleteN.e, pDiagN.e, pfileioN.e, pFind.e, pFixup.e (indirectly), pFloatN.e, pFPU.e (indirectly), pHeap.e, pInstance.e, pJcc.e, pJnotx.e, pLen.e, pMatch.e, pMath.e, pMem.e, pMkSqN.e, pPower.e, pprntfN.e, pProfile.e, pRand.e, pRepeatN.e, pRepeN.e, pRepsN.e, pRmdr.e, prtnidN.e, pSleep.e, psprintN.e, pStack.e, pSubseN.e, pSubssN.e, pThreadN.e, pTime.e, pTrace.e, pTrig.e, pType.e, puts1.e (indirectly), pUnary.e, pUnassigned.e, and pXor.e - they are all automatically included as and only when needed.

Most files in builtins\ are also autoincludes: database.e (except for db_fatal_id), dll.e (technically empty|now in VM\pcfunc.e), factorial.e, file.e, findrepl.e, gcd.e, get.e, graphics.e (technically empty|now in pscreen.e/pfileioN.e/pScrollN.e), image.e (apart from read_bitmap and save_bitmap, most things are now in pscreen.e anyway), log10.e, machine.e (though only int<-to->bits|bytes remain), matchrepl.e, misc.e, mouse.e (now empty, as it was all DOS-only), msgbox.e, pAlloc.e, panykey.e, pbreak.e, pcase.e, pchdir.e, pcolumn.e, pCrashN.e, pcurrdir.e, pdate.e, pdecodeflags.e, pdir.e, peekstr.e, pelapsed.e, penv.e, permute.e, pfactors.e, pfindany.e, pflatten.e, pgetpath.e, pincpathN.e, pmach.e, pmaths.e, pokestr.e, porall.e, ppp.e, premoveall.e, prnd.e, pscreen.e, pScrollN.e, pseqc.e, pseries.e, psmall.e, psplit.e, psqop.e, psum.e, ptagset.e, ptrim.e, pvlookup.e, read_lines.e, scanf.e, shuffle.e, sort.e, substitute.e, syswait.e, and wildcard.e - most of the other files in that directory are either incomplete or out of date and due for deletion. (ps: when I say empty I mean commented out) Likewise there is no need to remember to include anything in that list either (unless you need a namespace, in which case the error message will remind you what the filename is(/might) be).

Notable exceptions, that ship with phix but must be manually included, are:
arwen.ew, arwen32dib.ew, base64.e, bigatom.e, cffi.e, fileopenN.ew (and pComN.ew), pGUI.e, timedate.e, and timestamp.ew - a pretty short list.
Obviously you must manually include any files you create, unless you modify psym.e/syminit() and rebuild phix to make them autoincludes.

Compatibility Notes
[1] The relative directory handling (see ptok.e/initFilePathSet() for details) is not supported by either RDS Eu or OpenEuphoria. If you inspect the contents of the above mentioned stub, you will find perhaps a dozen other include statements that pre-load any sub-includes to work around that fact. Also, for compatibility reasons, the table of active directories is initially populated (in ptok.e\initFilePathSet) with content from the environment variables EUINC and EUDIR, but does not complain if they are not set. Lastly note that phix makes no attempt whatsoever to use any OpenEuphoria style eu.cfg files.

[2] Phix uses the directory as if it were part of the filename, allowing libX\misc.e, libY\misc.e, and libZ\misc.e to be simultaneously loaded, whereas RDS Eu\OpenEuphoria normally just use the filename. In some places I have used a forward slash trick to fool RDS Eu into including a duplicate filename twice. Another area where compatibility issues have have made a bit of a mess compared to a clean elegant phix-only style can be found at the top of edita.exw. All frightfully convoluted, I know, in fact includes files are the biggest stumbling block to getting an application to run on more than one of Phix/RDS Eu/OpenEu, entirely down to trial and error, and saying anything other than "look at the stub files for tips" is beyond the scope of this document.

[3] In phix, a namespace can be used to qualify a global defined either in the specified file or any files (indirectly) included by it. I think this is now supported by OpenEuphoria, but in RDS Eu no such sub-include handling occurs. Thus in Phix (and probably OpenEuphoria) you can code
    include arwen.ew as arwen   -- (includes arwen_misc.ew)
        ?arwen:hiWord(expr)
whereas to achieve the same effect in RDS Eu you would require
    include arwen.ew as arwen   -- (includes arwen_misc.ew)
    include arwen_misc.ew as misc
        ?misc:hiWord(expr)
[4] OpenEuphoria also permits a "namespace xxx" at the top of a file. Despite several reservations about such an approach, support for this has been added to phix, however there may be some idiosyncracies, especially with regards to using a local namespace to qualify locally declared identifiers, that I may have missed.

[5] OpenEuphoria has implemented a peculiar mixture of export/public/import/public import/public include and other pointless things, that I have long suspected cripple performance and serve little or no useful purpose. Phix just treats such things as "global" (except for "export" in the context of shared libraries), with no apparent ill effects thus far. As noted elsewhere, however, the contents of the OE std/ directory (and for that matter the include/ directory) are not compatible with phix, and care must be taken to avoid accidentally including them, instead of the (possibly incomplete) ones shipped with phix.

[6] OpenEuphoria has introduced countless cases of ambiguity. In the std/ directory, I can find potential clashes for clear, free, positive_int, add, subtract, diff, set, datetime, compare, get, close, find, find_all, split, create, close, info, new, size, format, parse, sum, wrap, encode, decode, is_match, and escape. I am trying to produce a phix-compatible version of std/, however it is not a high priority and may never quite finish. I can only apologise and warn you in advance that the above may cause issues, which namespaces may or may not be able to resolve. My advice is to comment out any and all include std/*, and see what happens.