As in other languages, when using record variables, one defines the new structured data type first and gives it a name, and then declares variables of that new data type.
For example, to define a new type named INFOLINE with four components, one would write the following:
TYPE INFOLINE
CHARACTER (LEN = 30) :: NAME
CHARACTER (LEN = 50) :: ADDRESS
INTEGER :: ZIP
INTEGER :: ACCNTNUM
END TYPE INFOLINE
The first two of the four components are character sections (with
names NAME and ADDRESS),
and the last two are integers (with names ZIP and
ACCNTNUM).
Fortran-90 does not allow the initialization of components of a derived type to a specific value, but Fortran-95/2003 permits such an initialization.
The following example declares variables of the derived data type defined in the previous section.
TYPE (INFOLINE) :: ACCOUNT, LIST(100), TEMP
Note that the second variable listed, LIST(100), is
an array of 100 elements of type INFOLINE. Each of the
100 elements has the four fields that are part of the new type.
ACCOUNT%ZIP
indicates the ZIP component of variable ACCOUNT
and
LIST(1)%ACCNTNUMindicates the ACCNTNUM component of the array element LIST(1). As in other languages, one uses the component part in accordance with its individual type definition. That is, if a component is an integer, such as ACCOUNT%ZIP, one uses it in the same way any integer would be used.
It is also permitted to assign a value to an entire structured variable by indicating the defined type on the right side of an assignment statement followed by values for each field in the variable enclosed in parentheses. For example, suppose we have defined a new type, called PERSON_INFO, which has components called NAME and PHONE, according to the following definition:
TYPE PERSON_INFO
CHARACTER (LEN = 30) :: NAME
CHARACTER (LEN = 10) :: PHONE
END TYPE PERSON_INFO
Assume the following declarations as well:
TYPE (PERSON_INFO) :: SAM CHARACTER*30 :: TEMPNAMEThen, assuming that TEMPNAME has been given a value, the following assignment is legal:
SAM = PERSON_INFO(TEMPNAME, '4085551212')
In practice, however, especially when using variables of the same derived type in more than one program segment, it is best to include the type definition in a module. This module can then be invoked by each program segment that uses variables of that user-defined type. (For more information about modules, see Chapter 9.)
It is also permitted, within a module, to designate some components of a derived type as PRIVATE, as the example in the next section shows. This may be done when components of a derived type are meant to be accessed only by module procedures, which themselves are PUBLIC. Note also that even though the components of a derived type may be designated as PRIVATE, the derived type itself (by default) remains a public entity and may be used whenever the module is imported in a program segment. Unless specifically designated as PRIVATE, all elements in a module are PUBLIC.
One may change the default attribute by merely listing the keyword PRIVATE in a module before any variables are declared. One can also specify certain declared identifiers to be PUBLIC or PRIVATE by listing them after the keyword in a declaration-type statement or by declaring the identifiers in a type declaration statement with PUBLIC or PRIVATE as an attribute. For example,
MODULE EXAMPLE1
PRIVATE
REAL :: A, B, C
REAL, PUBLIC :: X, Y, Z
INTEGER :: I, J, K
PUBLIC :: I, C
CONTAINS
SUBROUTINE SUB1
...
END SUBROUTINE
END MODULE
Here, A, B, J, K are all private because the
default attribute for the module was changed by the initial
PRIVATE statement (and the default was not
overridden via a specification statement). In contrast,
X, Y, Z, I, C are public (and therefore directly accessible
to any code making use of this module) because they
were explicitly given the attribute of PUBLIC when
declared or via the specification statement, thus overriding
the default.
15.6 Modules and Data Encapsulation
A major concern of contemporary programming style is the protection
of data structures from unintended and unplanned modification.
The practice of placing data structures within a larger structure, thereby
protecting the data, and allowing the information to be changed only
via specific subprograms, is commonly called data encapsulation.
Data encapsulation is foundational for "object-oriented programming"
since it enables programmers to write code in which data has been
protected and in which data is accessed only by specified subprograms.
It is possible to use modules to define a derived type and
also encapsulate the key components of the new type, protecting
these componenets from unintended changes. This is most easily done by
defining a derived type with private data components within a
module, and also including within the module local subprograms
which automatically have access to the private data components
of the derived type.
As an example, the following shows one approach for implementing
in Fortran-90/95/2003 the data structure referred to as a stack.
The underlying data structure is part of a derived type and this type
and associated subprograms are placed in a module called STACK_MOD.
The derived type is called STACK and its data, the array
STACKELEMENT which will contain the contents of the stack,
and the top-of-stack pointer TOP will be PRIVATE,
and therefore inaccessible to any
program segment which makes use of the derived type.
The module also contains three local routines: PUSH, which
adds elements to the stack; POP, which deletes the element
on the top of the stack; and INIT, which initializes a new
stack by correctly setting the TOP variable to 0. (This last
routine is needed in Fortran-90, since initializing a
component of a derived type is not allowed in Fortran-90, but this
feature has been included in Fortran-95/2003.)
MODULE STACK_MOD
TYPE STACK
PRIVATE
INTEGER :: STACKELEMENT(100)
INTEGER :: TOP
END TYPE
CONTAINS
SUBROUTINE INIT(S)
TYPE(STACK) :: S
S%TOP = 0
END SUBROUTINE
!
SUBROUTINE PUSH(S,ITEM)
TYPE(STACK) :: S
INTEGER :: ITEM
IF (S%TOP < 100) THEN
S%TOP=S%TOP+1
S%STACKELEMENT(S%TOP) = ITEM
ELSE
WRITE(*,*) "STACK OVERFLOW"
STOP
ENDIF
END SUBROUTINE
!
INTEGER FUNCTION POP(S)
TYPE(STACK) :: S
IF (S%TOP > 0) THEN
POP = S%STACKELEMENT(S%TOP)
S%TOP = S%TOP-1
ELSE
WRITE(*,*) "STACK UNDERFLOW"
STOP
ENDIF
END FUNCTION
END MODULE
The following program makes use of the STACK_MOD module
and declares two stacks, S and T. It then pushes a few
values onto the two stacks and pops the values off to
print them out. (For further information about stacks, see
a complete book on Data Structures.)
PROGRAM TESTSTACK
USE STACK_MOD
TYPE(STACK) S,T
INTEGER TEMP
! Initial both stackpointers
CALL INIT(S)
CALL INIT(T)
! Push several values onto the stacks
CALL PUSH(S,3)
CALL PUSH(S,4)
CALL PUSH(S,5)
CALL PUSH(T,1)
CALL PUSH(T,2)
! Pop a value off and save it in TEMP
! before printing it out
TEMP = POP(S)
WRITE(*,*) TEMP
! Pop off values and print out directly
WRITE(*,*) POP(S)
WRITE(*,*) POP(S)
WRITE(*,*) POP(T)
WRITE(*,*) POP(T)
END
This page is maintained by Dennis C. Smolarski, S.J.
dsmolarski@math.scu.edu
© Copyright 1999-2005 Dennis C. Smolarski, S.J., All rights reserved.
Last changed: 27 June 2005.