Declarations in a Fore.NET program are the constituent elements of the program. Fore.NET programs are organized using namespaces, which can contain type declarations and nested namespace declarations. Type declarations are used to describe classes, structures, interfaces, enumerations, and delegates. The kinds of members permitted in a type declaration depend on the form of the type declaration. For example, class declarations can contain declarations for constants, fields, methods, properties, events, and constructors.
A declaration describes a name in the declaration space, to which the declaration belongs. It is a compile-time error to have two or more declarations that introduce members with the same name in a declaration space. It is never possible for a declaration space to contain different kinds of members with the same name.
There are several different types of declaration spaces, as described below:
Global declaration space contains declarations that are not members of a namespace.
Each namespace creates its own declaration space.
Each declaration of a class, structure or interface creates a new declaration space.
Each enumeration creates a new declaration space, which members are named enumeration constants.
Each function member creates a new declaration space also known as local declaration space, which members are parameters and local variables.
The textual order, in which names are declared, is generally of no significance. Declaration order is significant in the following cases:
The declaration order for field declarations and local variable declarations determines the order, in which they are initialized.
The declaration order for named constants in an enumeration is significant, when declarations of their numeric values are omitted.
//A namespace is determined in the global namespace and creates a proper domain space
Namespace A
//Determine interface in the namespace
Interface ITest
End Interface;
//Determine class in the namespace
Class Test: ITest
End Class;
//Determine enumeration in the namespace
Enum Mode
//Determine enumeration elements
Low, Middle, High
End Enum;
End Namespace;
Namespaces and types consist of members. The members of an entity are generally available through the use of a qualified name that starts with a reference to the entity, followed by a "." token, followed by the member name.
Members of a type are either declared in the type or inherited from the base class of the type. When a type inherits from a base class, all members of the base class, except for constructors, become members of the derived type. The declared member access level does not affect their inheritance. However, a member may not be accessible in a derived type, either because of its declared access level or because it is hidden.
Namespaces, types and methods declared outside another namespace are global namespace members.
//Interface is a namespace member
Interface ITest
//Determine interface members that will be implemented in the class
Function Run(ExecuteParams: Mode): Integer;
Property Status: Integer
Get;
End Property Status;
End Interface;
//Class is a namespace member
Class Test1: ITest
//Determine class members
iResult: Integer;
iStatus: Integer;
Public Function Run(ExecuteParams: Mode): Integer;
Begin
iStatus := 0;
//...
Select Case ExecuteParams
//...
//Various variants of execution according to the input parameter value
//...
Case Mode.Low: iResult := 1;
Case Mode.Middle: iResult := 2;
Case Mode.High: iResult := 3;
End Select;
//...
iStatus := 100;
Return iResult;
End Function;
Public Property Status: Integer
Get
Begin
Return iStatus
End Get
End Property;
End Class;
//Enumeration is a namespace member
Enum Mode
//Determine enumeration elements
Low, Middle, High
End Enum;
Declarations of members enable control over member access. The visibility of a member is established by the access level stated in its declaration combined with the access level of the immediately containing type, if any.
The following access levels are possible:
Public, which is selected by including the Public modifier in the member declaration. In this case member access is not limited.
Protected, which is selected by including the Protected modifier in the member declaration. In this case member access is limited to the containing class or types derived from the containing class.
Assembly, which is selected by including the Friend modifier in the member declaration. In this case member access is limited to the assembly (program) in which it is declared.
Protected Assembly, which is selected by including the Protected Friend modifier in the member declaration. In this case member access is limited either to the current assembly or to the classes derived from the class containing this member, or to both conditions being met.
Private, which is selected by including the Private modifier in the member declaration. In this case member access is limited to the containing class.
Depending on the context, in which a member declaration takes place, only certain access modifiers are permitted. When a member declaration does not include any access modifiers, its visibility is determined by the default declared accessibility.
Namespaces implicitly have public declared access. No access modifiers are allowed on namespace declarations.
Types declared in compilation units or namespaces can have public or assembly declared access level. By default, they have assembly declared access level.
Class members can have any of the five kinds of declared access level and, by default, private declared access level.
Structure members can have public, assembly, or private declared access level, because structures are implicitly sealed types. By default, they have private declared access level.
Interface members implicitly have public declared access level. No access modifiers are allowed on interface member declarations.
Enumeration members implicitly have public declared accessibility. No access modifiers are allowed on enumeration member declarations.
A visibility scope of a member is a set of program sections, in which access to the member is permitted. For purposes of defining the visibility scope of various program members, a member is said to be nested if it is declared within another type. Other members (that are not declared within another type) we will call top-level members. The program text is declared as program text contained in all files of source text (compilation units). Text of a type is the entire text contained between the header and the End closing structure in class, structures, interface, or enumeration declarations.
The visibility scope of a standard type (such as Object, Integer or Double) is unlimited.
The visibility scope of a top-level type T in a program P is determined as follows:
If the declared access level of T is public, the visibility scope of T is the program text of P and any program that references to P.
If the declared access level of T is assembly, the visibility scope of T is the program text of P.
From these declarations it follows that the visibility scope of a top-level type is always at least the program, in which that type is declared.
The visibility scope of a nested member M declared in a type T within a program P is determined as follows:
If the declared access level of M is public, the visibility scope of M matches the visibility scope of T.
If the declared access level of M is a protected assembly, let D be the union of the program text of P and the program text of any type derived from T, which is declared outside P. The visibility scope of M is the intersection of the visibility scope of T with D.
If the declared access level of M is protected, let D be the union of the program text of T and the program text of any type derived from T. The visibility scope of M is the intersection of the visibility scope of T with D.
If the declared access level of M is assembly, the visibility scope of M is the intersection of the visibility scope of T with the program text of P.
If the declared access level of M is private, the visibility scope of M is the text of type T.
From these declarations it follows that the visibility scope of a nested member is always at least the program text of the type in which the member is declared. Furthermore, the visibility scope of a member is never more inclusive than the visibility scope of the type, in which the member is declared.
On calling the M type or member, the access is checked as follows:
If M is determined inside the type and the type is not accessible, the compilation error occurs.
If M has a public access level, the access is permitted, or:
If M has a protected assembly access level, the access is permitted if it occurs within the program, in which M is declared, or if it occurs within a type derived from the type, in which M is declared.
If M has a protected access level, the access is permitted if it occurs within the type derived from the type that contains declaration of M.
If M has an assembly access level, the access is permitted if it occurs within the program, in which M is declared.
If M has a private access level, the access is permitted if it occurs within the type, in which M is declared.
Otherwise, the type or member is not accessible, and a compile error occurs.
Specific structures in the language require a type to be at least as accessible as a member or another type. A type T is said to be at least as accessible as a member or type M if the visibility scope of T is a superset of the visibility scope of M. In other words, type T is to be accessible in all contexts, in which M is accessible.
The following constraints exist:
The parent class of a class type must be at least as accessible as the class type itself.
The base interface of an interface type must be at least as accessible as the interface type itself.
The return type and parameter types of a delegate type must be at least as accessible as the delegate type itself.
The type of a constant must be at least as accessible as the constant itself.
The type of a field and parameter types of a field must be at least as accessible as the field itself.
The return type and parameter types of a method must be at least as accessible as the method itself.
The type of a property must be at least as accessible as the property itself.
The type of an event must be at least as accessible as the event itself.
The parameter types of an instance constructor must be at least as accessible as the instance constructor itself.
Methods, instance constructors, and properties are characterized by their signatures:
The signature of a method consists of the name of the method and the type and kind (value, reference, or output) of each of its formal parameters, considered in their declaration order from left to right. The signature of a method specifically does not include the return type, nor does it include the ParamArray modifier that may be specified for the right-most parameter.
The signature of an instance constructor consists of the type and kind (value, reference, or output) of each of its formal parameters, considered in order from left to right. The signature of an instance constructor specifically does not include the ParamArray modifier that may be specified for the right-most parameter.
The signature of a property consists of the name of the property and the type and kind (value, reference, or output) of each of its formal parameters, considered in their declaration order from left to right. The signature of a property specifically does not include its type, nor does it include the ParamArray modifier that may be specified for the right-most property parameter.
Signatures enables the use of overloading of members in classes, structures, and interfaces. Overloading permits a class, structure, or interface to declare multiple members of the same kind (method, event, or constructor) with the same name, provided their signatures differ.
Note that the members declared in the same type cannot have signatures that differ only in the presence of modifiers Var and Out. Successful compilation requires some other differences.
The scope of a name is the region of program text, within which it is possible to use this name without its qualification. Scopes can be nested, and an inner scope may redetermine the meaning of a name from an outer scope. The name from the outer scope is then said to be hidden, and access to the outer name is only possible by qualifying the name.
Name hiding occurs when scopes of names of different program entities overlap through inheritance or nesting.
Hiding through nesting. Name hiding through nesting can occur as a result of nesting namespaces or types declared within namespaces, and as a result of the method parameter and local variable declarations.
Hiding through inheritance. Name hiding through inheritance occurs when classes or structures redetermine names that were inherited from base classes.
Several contexts in program require a namespace name or a type name to be specified. Either form of a name is written as one or more identifiers separated by points.
namespace-name:
namespace-or-type-name
type-name:
namespace-or-type-name
namespace-or-type-name:
identifier type-argument-listopt
namespace-or-type-name . identifier type-argument-listopt
Every namespace and type has a fully qualified name (full name), which uniquely identifies the namespace or type amongst all others. The fully qualified name of a namespace or type N is determined as follows:
If N is a member of a global namespace, its fully qualified name is N.
Otherwise, its fully qualified name is S.N, where S is the fully qualified name of the namespace or type in which N is declared.
The Fore.NET language implements automatic memory control. A developer does not need to manually select memory for objects and release it when an object is not longer used. Automatic memory control is executed by garbage collector. Object life cycle looks as follows:
On creating an object a constructor is executed, memory is selected, and access is given to the object object instance.
The compiler and garbage collector track object links.
If an object is no longer used or not available, decomposer is automatically called for it.
After the decomposer worked, the object is considered to be deleted and is not longer available.
Later, the garbage collector releases memory related with this object.
The garbage collector saves information about objects and uses it to make decisions and control memory. Automatic memory control is executed on working with objects developed in application code in the Fore.NET language. In some cases forced garbage collector control may be required, this is implemented by means of the System.GC (mscorlib.dll) class methods. For example, on working with repository system objects, which kernel is developed by means of COM technology.
Public Shared Sub Main(Params: StartParams);
Var
//...
MB: IMetabase;
Report: IPrxReport;
//...
Begin
//...
MB := Params.Metabase;
Report := MB.ItemById["Report"].Bind() As IPrxReport;
//...
//Working with report and data contained in it
//...
//Release object
Report := Null;
//Garbage collecting, memory release, which was selected for report and data
System.GC.Collect();
//...
//Further working with repository and other objects
//...
End Sub;
On working with COM objects to release them in time, use the System.Runtime.InteropServices.Marshal.ReleaseComObject method. Working with resources of the Fore language from Fore.NET may also require forced garbage collecting. The CollectFullGarbage and CollectGarbage methods are used for these purposes. For details about these methods read the Using Resources of Foresight Analytics Platform in External Applications > Garbage Collection knowledgebase article.