[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The basic compilation unit in the Q language is the script, which is simply a (possibly empty) sequence of declarations and definitions in a single source file:
script : {declaration|definition} |
In order to make a given set of definitions available for use in the interpreter, you can just collect the relevant declarations, variable definitions and equations in a script which you submit to the interpreter for execution. The interpreter in turn invokes the compiler to translate the script into a bytecode file which is loaded by the interpreter (see Using Q). A script may also be empty, in which case it does not provide any definitions at all.
If you put all your definitions into a single script, that's all there is to it. However, you will often want to break down a larger script into a collection of smaller units which can be managed separately and which are linked together by the compiler into a single bytecode file. To these ends the Q language allows you to put your definitions into several separate script files, which are also called modules. To gain access to the function, variable and type symbols provided by another module, you must then use an import or include declaration, using the following syntax:
declaration : unqualified-import | qualified-import unqualified-import : 'import' module-spec {',' module-spec} ';' | 'include' module-spec {',' module-spec} ';' qualified-import : 'from' module-spec 'import' [symbol-specs] ';' | 'from' module-spec 'include' [symbol-specs] ';' module-spec : module-name ['as' unqualified-identifier] module-name : unqualified-identifier | string symbol-specs : symbol-spec {',' symbol-spec} symbol-spec : unqualified-identifier ['as' unqualified-identifier] | unqualified-opsym ['as' unqualified-opsym] |
As of version 7.8, Q supports both unqualified and qualified import clauses. The former allows you to quickly import an entire collection of modules, while the latter gives you precise control over which symbols are to be imported from which modules. We describe each of these in turn.
4.1 Unqualified Imports | ||
4.2 Qualified Imports | ||
4.3 Implicit Imports and the Prelude | ||
4.4 The Global Namespace |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Easiest first, let as take a look at unqualified imports. The following
declaration imports two modules foo
and bar
:
import foo, bar; |
If you put such declarations into your "main script" and then run the script with the interpreter, the imported modules will be loaded as well.
To determine which functions, variables and types are actually available to be imported into another script, the Q language allows you to declare symbols either as "public" or "private", see Declarations. Outside a module, only the public symbols are accessible when the module is imported in another module.
Normally import is not "transitive", i.e., importing a module
foo
does not automatically give you access to the symbols
imported by foo
, but only to the public symbols declared in
foo
itself. To work around this, instead of import
you
can also use an include
declaration which causes all imports and
includes of the included module to be "reexported". For instance, let
us consider the case that module foo
includes module bar
:
include bar; |
Then by importing module foo
you also gain access to the public
symbols of module bar
(and, recursively, to the modules included
by bar
, etc.). This provides a means to group different modules
together in one larger "umbrella" module. For instance, the standard
prelude script (cf. The Standard Library) simply includes most of
the other standard library modules.
In the Q language, each module has its own separate namespace. This
means that two different modules, say foo1
and foo2
, may
both provide their own public function symbol named foo
. If both
foo1
and foo2
are imported in the same script, you can
distinguish between the two by using a qualified identifier, using
the module name as a prefix, e.g., foo1::foo
or
foo2::foo
. (Writing simply foo
in this case will produce
an error message because the reference is ambiguous.)
Import and include declarations can occur anywhere in a script (and will
be active from this point on up to the end of the script file), but it
is common (and recommended) practice to put them near the beginning of
the script. As in most other programming languages, module dependencies
must always be acyclic. If the compiler finds a cyclic chain of
import
and include
declarations, such as a module
importing itself or a module foo
importing a module bar
which in turn imports foo
again, it produces an error message.
Another caveat: When using unqualified import clauses, it is much too
easy to accidentally "reuse" an imported symbol because of a missing
local symbol declaration. For instance, if you import a module
foo
which happens to export a symbol bar
, and then you
later define a function bar
in your script, your definition will
use the imported bar
symbol. This is perfectly legal in Q, and
may be intended, but if it's not then you have to explicitly declare a
new local bar
symbol after the import clause,
cf. Declarations. If you forget this, you will errorneously
redefine the existing bar
function instead. One way to avoid this
is to always use qualified imports, as described below. Another
possibility is to run the interpreter with the --pedantic
option,
in which case it will warn you about symbols from unqualified imports
which are referred to with unqualified identifiers, see Running Compiler and Interpreter, for details.
As indicated in the syntax rules, the names of the modules to be imported can either be specified using an unqualified identifier, or a string denoting a full or relative pathname, e.g.:
import "/home/ag/q/stuff.q"; |
In this case, you can also omit the `.q' suffix, it will be
supplied automatically when necessary. Moreover, the module identifier
is automatically the basename of the script filename (i.e., stuff
in the above example); therefore, it is a good idea to choose basenames
which are legal Q identifiers so that you can use them in qualified
symbols.
If no absolute path is specified, the interpreter locates script files using its "search path", which usually contains the current directory and other system-dependent or user-defined locations where "library" scripts are kept, see Using Q, for details.
The `as' keyword can be used to explicitly specify an unambiguous module name. This is useful, in particular, if the basename of the module is not a valid identifier, and for the purpose of resolving name clashes. For instance:
import "my/stdlib.q" as mystdlib; |
Simply importing "my/stdlib.q"
under its own name in this case
would produce an error message, because the name of the module collides
with the standard library module of the same name, and the compiler
enforces that all module names are unique.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A qualified import takes the form:
from foo import foo, BAR; |
This specifically imports the symbols foo
and BAR
from
module foo
, and nothing else. What this actually does is to
"redeclare" the imported symbols in the namespace of the importing
module, as explained in Cross-Checking of Declarations and Aliases, so that they look like private symbols of the importing
module. Thus you can refer to them, e.g., simply as foo
or with
the qualified name gnats::foo
, where gnats
is the name of
the importing module. Note that foo::foo
will not
work in this case, because a qualified import does not bring the
module itself into scope. (However, as pointed out below you can use
both a qualified and an unqualified import in concert to make
both gnats::foo
and foo::foo
work.)
A note on terminology: In Q parlance, the terms qualified import and unqualified import apply to the import clauses themselves; a qualified import clause is called "qualified" simply because it restricts the set of imported symbols. Unqualified and qualified identifiers can be used with both styles of import clauses alike.
As with unqualified import, there is a second kind of qualified import clause which also reexports the imported symbols, by making them public members of the importing module:
from foo include foo, BAR; |
For convenience, you can also write:
from module import; |
or
from module include; |
without listing any symbols to just import or include all symbols of the given module qualified. (It goes without saying that this should be used with care.) This is roughly equivalent to `import module' or `include module', respectively, but the imported symbols are made available as members of the namespace of the client, not the imported module.
If this sounds a bit confusing, here is an example which should clarify
the differences between unqualified and qualified imports. Let's assume
the following three modules A
, B
and C
:
/* A: */ import B; /* B: */ include C; /* C: */ public foo; |
Using this setup, the symbol foo
is available as either just
`foo' or as `C::foo' in all of A
, B
and
C
. Now suppose we change module B
to use a qualified
`include' instead:
/* B: */ from C include foo; /* or just: from C include; */ |
C
's namespace hasn't changed, of course, but in both A
and
B
the symbol foo
is now available as `foo' or
`B::foo', but not as `C::foo' anymore. However, you can
also combine unqualified and qualified imports, like this:
/* B: */ include C; from C include foo; |
Now the symbol foo
is available as either `foo',
`B::foo' or `C::foo' in B
and C
(and the
compiler will recognize it as the same symbol no matter which notation
you use).
Finally, note that since symbols imported using a qualified clause
become members of the importing namespace, they must not collide with
other symbols declared either locally or in another qualified import
clause. Thus, if you have two modules foo1
and foo2
which
both export their own (local) symbol foo
, the following will
provoke an error message from the compiler because of the clash between
the two different foo
symbols:
from foo1 import foo; from foo2 import foo; |
In such cases you must either use unqualified import, or employ an `as' clause to rename the symbols while importing them. E.g.:
from foo1 import foo as foo1; from foo2 import foo as foo2; |
Note that this is only a problem if the imported symbols are really distinct. If the symbols are just different "aliases" of the same symbol defined elsewhere, then you can just import them under the same name into the same scope without any problems.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Actually, there is yet another kind of import, namely the implicit
import of the prelude.q
script at the beginning of each script,
which in turn includes most standard library modules (see The Standard Library) and makes them readily available in your program,
without having to use an explicit import declaration. When looking up an
unqualified symbol in a given script, the compiler first searches for a
symbol defined in that script, then for a symbol in an imported or
included module, then for a symbol defined by the prelude and its
includes, and finally for a built-in symbol.
You can instruct the compiler to inhibit the default import of the
prelude, by using the --no-prelude
option, see Using Q. Moreover, you can also override the standard prelude with your own,
if it occurs on the search path before the standard prelude, see
Setting up your Environment.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The namespace available in the interpreter is always that of the main
script, i.e., the script given on the command line. This namespace also
includes the built-in namespace which contains all the built-in
symbols, as well as the implicit imports, i.e., the prelude and all its
includes (unless the --no-prelude
option was used). The built-in
namespace can be accessed explicitly by using an empty module qualifier,
as in ::sin
. Qualified prelude symbols use the corresponding
module name as the qualifier (e.g., stdlib::cat
), just as with
explicit imports.
The interpreter also allows you to dynamically import additional modules
in the global scope using the import
command, see Command Language. Moreover, to facilitate testing and debugging, in the
interpreter it is possible to gain access to all public and
private symbols of the program (also in modules not directly imported in
the main script) using qualified identifiers.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Albert Gräf on February, 23 2008 using texi2html 1.76.