Packages in Object Icon provide two functions :-
A file is declared to be in a package by simply adding a package declaration at the top of the source file, such as the following :-
package my.pack import io(write) procedure one() write("in my.pack.one") end
This will have the effect of adding the file to the package
my.pack. This information is stored in a file named
packages.txt, stored in the same directory as the ucode file. The format of the file is very simple, and just maintains a list of which files are in which package.
The other effect of the package statement is that the names of the global symbols (procedures, records, classes and global variables) declared in the file are prefixed automatically with the package name. So, the procedure
one in the above file is in fact named
A package is used in a program via the import statement. For example :-
import my.pack procedure main() one() end
The import statement causes the linker to search all the
packages.txt located on the linking path for the specified package. When found, all of the files in the package are linked into the program.
Note that the reference to the procedure
my.pack.one is in the shorter form,
one. This is allowed so long as there isn't another symbol
one which would make the reference ambiguous. In any case, the fully qualified form is also acceptable.
If there are several imports in one file it may become difficult to discern which symbol came from which package. For this reason, the import statement lets you indicate which symbols are being used from a particular package, as follows :-
import my.pack(one, two, three)
This means the three given symbols are being used in the source file and can be resolved to
my.pack.three respectively. If there were another symbol in
four, then it would not be resolved by the linker if it were encountered as
four; rather an undeclared identifier error would be raised. If it were encountered as
my.pack.four however, that would not raise an error. Note that this form of the import statement still links all of the files in the package into the program, regardless of which symbols are specified.
Sometimes it is necessary to use a fully-qualified symbol; in particular it may be necessary if you have imported two packages which both contain the same symbol. For example, consider the following program which imports two packages each of which contains a symbol named
import lang, parser, io(write) procedure main() write(image(Class)) end
Compiling this produces an error message (on linking) :-
/tmp/junk.u: File junk.icn; Line 4 # Symbol 'Class' resolves to multiple targets in procedure main :- lang.Class (/opt/objecticon/lib/main/class.icn; Line 7) parser.Class (/opt/objecticon/lib/parser/tree.icn; Line 723) 1 error
Supposing we meant
parser.Class, we can just change the offending line to :-
Note that we still need the
import parser. Otherwise
parser is interpreted as an identifier and
Class as a field, and an "Undeclared identifier" error is produced by the linker.
Another way to resolve the ambiguity would be to use qualified imports. For example, the following program compiles successfully with the use of
Class unambiguously resolving to
import lang(to_string), parser(Class), io(write) procedure main() write(to_string(Class)) end
If you use a fully-qualified symbol in a superclass list, or an invocable declaration, then the package must be imported. For example, consider the following file :-
class Abc(xml.Node) end
Translating this will give the following error :-
File junk.icn; Line 1 # Reference to unimported package: 'xml'
This can be resolved by simply importing the
xml package, either as a qualified or unqualified import. The reasoning behind this error is to avoid library code which translates correctly to a
.u file, but depends on some other file, or the client program, importing (and hence linking) a particular package.
Top-level declarations can be specified as having package scope; for details see here.Contents