In what follows, readers who are familiar with Fortran 95 derived types and pointers may find it helpful to draw an analogy with the following fragment of code.
!Stage 1: Define a derived type.
TYPE(Circle)
INTEGER x,y,r
END TYPE
!Stage 2: Declare a Fortran pointer to a Circle.
TYPE(Circle),POINTER::C
!Stage 3: Allocate memory and use the TYPE constructor.
ALLOCATE(C)
C=Circle(1,1,1)
In FTN95 code, the keyword OBJECT is used to declare an alias for an object whose class is defined externally (see .NET Objects). This is equivalent to Stage 2 in the above fragment. The use of OBJECT does not allocate memory for the object's data.
Typically classes are accompanied by one or more methods called constructors that initialise the object's data and define its initial state. In FTN95 the keyword NEW@ is used to allocate memory for an object's data and to call one of its constructors.
For example:
OBJECT("System.Object") OBJ
OBJ=NEW@("System.Object")
Using NEW@ performs the equivalent of Stage 3 in the above fragment. If a constructor takes arguments, these are added to the call to NEW@ after the class name of the .NET object ("System.Object" in this example).
Note that the use of OBJECT declares a variable of Fortran pointer type but leaves it undefined. Using NEW@ is equivalent to using ALLOCATE (i.e. a pointer assignment) followed by a call to the constructor.
As in this example, the class name that is used in NEW@ is usually the same as the class name that is used in OBJECT(...). However, .NET objects exist in an inheritance hierarchy and as a result the class name in NEW@ can be one that is derived from that used in OBJECT(...). Thus, the following code fragment is legal:
OBJECT("System.Object") OBJ
OBJ=NEW@("System.String")
because "System.String" is derived from "System.Object". After the call to NEW@, OBJ is an alias for a .NET string object.
The keyword CAST@ is used when creating an alternative alias for a .NET object as illustrated by the following fragment.
OBJECT("System.Object") OBJ
OBJECT("System.String") STR
OBJ=NEW@("System.String")
STR=CAST@(OBJ,"System.String")
The assignment in the last line is a pointer assignment that makes STR an alternative alias for OBJ (memory for the object has been allocated by using NEW@ on the line before). In a Standard Fortran context the assignment would take the form STR= >OBJ. STR and OBJ are alternative names for the same object in memory.
N.B. Although the above fragment illustrates a principle, it does not represent a practical method for accessing .NET strings. For further information see .NET string type.
An exception is raised (at runtime) if you use CAST@ with incompatible arguments (e.g. if "System.String" was not derived from "System.Object").
NEW@ can be called in the context of a call to another function. For example,
LIBRARY "MyLib.dll"
LIBRARY "System.Windows.Forms.dll"
ASSEMBLY_EXTERNAL(NAME="System.Windows.Forms.Application.Run") MyRun
CALL MyRun(NEW@("MyLib.MyForm"))
In this code MyRun is an alias for an overloaded static method. In one overloaded case, it can take a single argument that is a reference to a Microsoft Form. MyForm is assumed to be a class defined in MyLib that is derived from the Form class. NEW@ can be used in this context despite the fact that the argument does not provide a direct type match. This is because FTN95 type matching permits a match with a class that is derived from the given argument class.
In standard Fortran, P%NAME selects the data member called NAME for an instance P of a derived type. In FTN95, the '%' operator can also be used to access data members of .NET objects assuming that such members have meaningful Fortran types. For example:
OBJECT("System.String") STR
STR=NEW@("System.String","alpha")
PRINT*,STR%Length
END
In this case using a second string argument for NEW@ calls a constructor that initialises the string. Length is a data member of System.String so the value 5 (the length of "alpha") is printed. In fact Length is an example of a particular kind of data member that is called a property. A property is not accessed directly but via a method belonging to the class and as a result can be made to be read-only or write-only. In this case Length is read-only and the following fragment would fail to compile
STR%Length=7
If a simple (non-property) data member of a .NET object is passed as an argument to a routine then (since it is passed by reference) it can be used and/or altered by the routine. However, a property is first evaluated and stored locally before the address of the local store is passed by reference. Consider for example:
CALL FOO(STR%Length)
This code will compile and the routine FOO could both use and alter the associated dummy argument. However, any change will not be reflected back to STR. In other words the argument is effectively passed by value. See .NET string type for a much easier way to use .NET strings.
It is important to realise that Fortran variables are not case-sensitive. All names are converted by the compiler to upper case (only characters within quoted strings are case-sensitive). Thus STR%Length is exactly the same as STR%LENGTH. The compiler uses a case-insensitive search when it looks for a member of a .NET class. This is usually adequate, but an alternative syntax is provided to cater for classes that contain members that differ only by case. The alternative uses a quoted string. For example, STR%'Length' or STR%"Length". Only literal strings are permitted in this context. Character expressions and parameters cannot be used.
.NET classes can have both private and public data members and only public data members can be accessed directly from outside of the class (private members can only be accessed by and via the given methods of the class).