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. A compilation error occurs if there are two or more declarations that introduce members with the same name in a declaration space. It is also not allowed 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 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.
//The A namespace is determined in global namespace and creates a proper domain space
Namespace A
//Determine interface in namespace
Interface ITest
End Interface;
//Determine class in namespace
Class Test: ITest
End Class;
//Determine enumeration in 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.
Type members are either declared in the type or inherited from the basic class of the type. When a type inherits from a basic class, all members of the basic 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 - namespace member
Interface ITest
//Determine interface members that will be implemented in class
Function Run(ExecuteParams: Mode): Integer;
Property Status: Integer
Get;
End Property Status;
End Interface;
//Class - 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 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 - namespace member
Enum Mode
//Determine enumeration elements
Low, Middle, High
End Enum;
Declarations of members enable control over member access. The member visibility is determined by the access level specified in its declaration combined with the access level of the immediately containing type, if any.
There are the following access levels:
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 member visibility scope is a set of program parts, in which access to the member is allowed. 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 compilation 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 basic 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:
A method signature consists of method name and types and kinds (by value, reference, or output) of each of its formal parameters considered in their declaration order from left to right. The method signature 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 types and kinds (by 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 property name and types and kinds (by 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 enable 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 the Var and Out modifiers. Successful compilation requires some other differences.
A 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 basic 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 or type has a fully qualified name (full name), which uniquely identifies the namespace or type amongst all others. A fully qualified name of a namespace or N type 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 no longer used. Automatic memory control is executed by garbage collector. An object life cycle looks as follows:
On creating an object a constructor is executed, memory is selected, and access is given to the 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 no 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;
//...
//Work with report and data contained in it
//...
//Release object
Report := Null;
//Garbage collection, memory release, which was selected for report and data
System.GC.Collect();
//...
//Further work with repository and other objects
//...
End Sub;
When 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 see the Using Resources of Foresight Analytics Platform in External Applications > Garbage Collection knowledgebase article.
See also: