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.
NB 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
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 (nb not pwa/p2js compatible) 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 that 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(), or if you prefer, format_date() and format_time() - 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 note[7] below).
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.
(Note these lists are not well maintained, for the definitive version see psym.e/syminit(), and possibly pwa/src/p2js_auto.e)
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 (also) 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,
pFixup.e (indirectly), pFloatN.e, pFPU.e (indirectly), pHeap.e, pInstance.e,
pJcc.e, pJnotx.e, pLen.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: base64.e,database.e (except for db_fatal_id), dict.e, dll.e (technically empty|now in VM\pcfunc.e), factorial.e,
file.e, find.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), match.e, matchrepl.e, misc.e,
mouse.e (now empty, as it was all DOS-only), msgbox.e, ordinal.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, pqueue.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, scanf.e,
shuffle.e, sort.e, substitute.e, syswait.e, unit_test.e, utfconv.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:
cffi.e,complex.e, dos_rescue.ew, fileopenN.ew (and pComN.ew), get.e, ipc.e, json.e, libcurl.e,
librsvg.e, LiteZip.e, mpfr.e, pGUI.e, pSQLite.e, pipeio.e, reflections.e, regex.e,
serialize.e, sockets.e, timedate.e, timestamp.ew, and xml.e - a pretty short list.
(There are also some deprecated components: arwen.ew,arwen32dib.ew, bigatom.e, msgbox.e, nopoll.e, and
win32lib.ew.)
Obviously you must manually/explicitly include any files you create, unless you were to 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 Euphoria. If you inspect the contents of the above mentioned stub (demo\arwendemo\arwen.ew), 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 Euphoria 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 all be simultaneously loaded, whereas Euphoria normally just uses 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 both Phix and Euphoria, 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 in the latest version of by Euphoria, but in RDS Eu no such sub-include handling occurred. Thus in Phix (and probably Euphoria) you can code
[5] Euphoria 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 Euphoria 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] Euphoria 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.
[7] While phix.chm can (and does) contain some "see also" links, or could contain some wikipedia-style "disambiguation" pages, or be coerced into coping with a handful of exact namespaces, one thing it certainly cannot do is analyse the current project’s include statements, or even be passed such an analysis, to figure out precisely what some user-defined and non-standard namespace actually means.
Not that I believe anyone has ever tried, but you can theoretically bolt in a custom help file (or 38) to the Edita/Edix help lookup system(s), simply by creating a chm file along with a (non-clashing) sister-file to and in the same directory as the existing help/Phix.txt. However, there is of course no mechanism whatsoever for the editor to determine which of your 38 custom help files the "new" currently under the cursor should open [on F1], should that "new" not be unique.
pwa/p2js: JavaScript is essentially a function-scoped language, with block scope added as a bit of an afterthought. In particular everything declared at file level is effectively global, and there are no namespaces at all. Several of the files in builtins\ and particularly builtins\VM are wholly incompatible with the transpiler. There is a hand crafted pGUI.js alternative to pGUI.e, and a similar mpfr.js alternative to mpfr.e, both of which are handled seamlessly/automatically for you, as are (or should be) every file in builtins\[VM] that contains one or more #ilASM{} statement. In addition, several other files in the builtins\ directory also get an "insert_dollars()" treatment, to prevent potential clashes.
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.
NB 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.ewand 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 (nb not pwa/p2js compatible) 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 that 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(), or if you prefer, format_date() and format_time() - 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 note[7] below).
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.
(Note these lists are not well maintained, for the definitive version see psym.e/syminit(), and possibly pwa/src/p2js_auto.e)
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 (also) no need to worry about or remember the names of any of: pApnd.e,
Most files in builtins\ are also autoincludes: base64.e,
Notable exceptions, that ship with Phix but must be manually included, are:
cffi.e,
(There are also some deprecated components: arwen.ew,
Obviously you must manually/explicitly include any files you create, unless you were to 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 Euphoria. If you inspect the contents of the above mentioned stub (demo\arwendemo\arwen.ew), 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 Euphoria 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 all be simultaneously loaded, whereas Euphoria normally just uses 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 both Phix and Euphoria, 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 in the latest version of by Euphoria, but in RDS Eu no such sub-include handling occurred. Thus in Phix (and probably Euphoria) 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] Euphoria 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] Euphoria 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 Euphoria 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] Euphoria has introduced countless cases of ambiguity. In the std\ directory, I can find potential clashes for clear,
[7] While phix.chm can (and does) contain some "see also" links, or could contain some wikipedia-style "disambiguation" pages, or be coerced into coping with a handful of exact namespaces, one thing it certainly cannot do is analyse the current project’s include statements, or even be passed such an analysis, to figure out precisely what some user-defined and non-standard namespace actually means.
Not that I believe anyone has ever tried, but you can theoretically bolt in a custom help file (or 38) to the Edita/Edix help lookup system(s), simply by creating a chm file along with a (non-clashing) sister-file to and in the same directory as the existing help/Phix.txt. However, there is of course no mechanism whatsoever for the editor to determine which of your 38 custom help files the "new" currently under the cursor should open [on F1], should that "new" not be unique.
pwa/p2js: JavaScript is essentially a function-scoped language, with block scope added as a bit of an afterthought. In particular everything declared at file level is effectively global, and there are no namespaces at all. Several of the files in builtins\ and particularly builtins\VM are wholly incompatible with the transpiler. There is a hand crafted pGUI.js alternative to pGUI.e, and a similar mpfr.js alternative to mpfr.e, both of which are handled seamlessly/automatically for you, as are (or should be) every file in builtins\[VM] that contains one or more #ilASM{} statement. In addition, several other files in the builtins\ directory also get an "insert_dollars()" treatment, to prevent potential clashes.