***allocatable
ALLOCATABLE

An object with the allocatable attribute is allowed to
have a specified amount of storage allocated and then
deallocated using the ALLOCATE and DEALLOCATE statements.

An allocatable object is also known as a "dynamic object"
as opposed to a "static object".  The difference between
dynamic and static is the difference between deciding how
big an array is "while the program is running" versus
deciding how big an array is "in the array declaration
when you write the program."

Beginner note: Sometimes you know how big an array needs
to be.  For example, an array of seats in an auditorium.
Other times, you may need an array to grow or shrink.
For example, a phone book.  An auditorium has a fixed
number of seats, maybe 50 across and 100 deep; a phone
book has a "dynamic" number of people in it, maybe 5000
people one year and then 7000 people the next year.

EXAMPLES
--------

 real, allocatable, dimension(:)   :: dynamic_1_dim
 real, allocatable, dimension(:,:) :: dynamic_2_dim
 real, dimension(10)   :: static_1_dim
 integer, dimension(ACROSS, DEEP) :: static_2_dim

LOCATION
--------

 YES  1. In a program.
 YES  2. In a module and above the CONTAINS stmt, if any.
 YES  3. In a module, below the CONTAINS stmt, and
         in a procedure.
  NO  4. In a defined type.

 Specifically: Any declaration outside a type definition
 can have ALLOCATABLE subject to the below table.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable
  dimension           ALWAYS
  intent              NEVER
  optional            NEVER
  parameter           NEVER
  pointer             NEVER
  private             SOMETIMES
  public              SOMETIMES
  save                SOMETIMES
  target              SOMETIMES

  Initialization, with an = on the right of the ::,
  is NEVER allowed with the allocatable attribute.

***dimension
DIMENSION

An object with the dimension attribute is an array.  An
"array" holds zero to many values as opposed to a "scalar"
which holds one value.  An array can be one dimensional
(for example, a single-file line of chairs), two
dimensional (for example, the chairs in a classroom),
three dimensional (for example, the chairs in a row of
classrooms), all the way up to seven dimensions.

Beginner note: It is possible to write programs without
using arrays, but most programs require handling lots of
information; this information is stored in arrays.  For
example, all the students in a class or a school would be
an array of students; all the seats on a bus would be an
array of seats; all the people in a phone book would be an
array of people; all the cards in a deck of cards would be
an array of cards.

EXAMPLES
--------

 integer, allocatable, dimension(:) :: single_file_dynamic
 integer, dimension(52) :: deck_of_cards
 integer, dimension(ACROSS, DEEP) :: classroom_chairs
 integer, dimension(ROOMS, ACROSS, DEEP) :: hallway_chairs
 integer, dimension(HALLS, ROOMS, ACROSS, DEEP) :: chairs

LOCATION
--------

 YES  1. In a program.
 YES  2. In a module and above the CONTAINS stmt, if any.
 YES  3. In a module, below the CONTAINS stmt, and
         in a procedure.
 YES  4. In a defined type.

 Specifically: Any declaration can have DIMENSION.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         SOMETIMES
  dimension           
  intent              SOMETIMES
  optional            SOMETIMES 
  parameter           SOMETIMES
  pointer             SOMETIMES
  private             SOMETIMES
  public              SOMETIMES
  save                SOMETIMES
  target              SOMETIMES

  Initialization, with an = on the right of the ::,
  is allowed with the dimension attribute.

***intent
INTENT

An object with the intent attribute is an argument of a
procedure.  All procedure arguments are required to have
the intent attribute.  In a subroutine, the intent is one
of three possibilities:
  intent(in)
  intent(inout)
  intent(out)
In a function, the intent must be
  intent(in)

All procedure arguments have exactly one intention.
 IN,    value comes in and must not change
 INOUT, value comes in and it can change before going out
 OUT,   no value comes in, but a value can go out

Intermediate note: If a procedure argument is a pointer,
it is not allowed to have the intent attribute.

Advanced note: If a procedure argument is a procedure, it
is not allowed to have the intent attribute.

EXAMPLES
--------

 integer, intent(in)  :: a,b,c
 real,    intent(out) :: average_of_abc
 real,    intent(inout) :: current_total

LOCATION
--------

  NO  1. In a program.
  NO  2. In a module and above the CONTAINS stmt, if any.
 YES  3. In a module, below the CONTAINS stmt, and
         in a procedure.
  NO  4. In a defined type.

 Specifically: Only procedure arguments can have INTENT,
 and procedure arguments must have INTENT.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         NEVER
  dimension           SOMETIMES
  intent
  optional            SOMETIMES 
  parameter           NEVER
  pointer             NEVER
  private             NEVER
  public              NEVER
  save                NEVER
  target              SOMETIMES

  Initialization, with an = on the right of the ::,
  is not allowed with the intent attribute.

***optional
OPTIONAL

An object with the optional attribute is an argument to a
procedure that is not required to be supplied in a call to
this procedure.  Only procedure arguments are allowed to
have the optional attribute.

Beginner note: You may write many procedures without ever
specifying the optional attribute.  If you are writing a
procedure, however, that is called from places that do not
need to supply all the procedure arguments, it is good
documentation to make the "sometimes not needed arguments"
optional arguments.  Good documentation means that you are
supplying information for the reader of your code.

Intermediate note: If a procedure argument is optional,
you will likely have a reference to the PRESENT intrinsic
procedure which tells you whether or not the optional
argument was supplied.

EXAMPLES
--------

 logical, intent(in),    optional :: is_rabbit
 real,    intent(out),   optional :: rabbit_weight
 integer, intent(inout), optional :: num_of_babies

  if (present(num_of_babies)) then
     call UpdateTotalRabbits(num_of_babies)

LOCATION
--------

  NO  1. In a program.
  NO  2. In a module and above the CONTAINS stmt, if any.
 YES  3. In a module, below the CONTAINS stmt, and
         in a procedure.
  NO  4. In a defined type.

 Specifically: Only procedure arguments can have OPTIONAL.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         NEVER
  dimension           SOMETIMES
  intent              ALWAYS
  optional            
  parameter           NEVER
  pointer             SOMETIMES
  private             NEVER
  public              NEVER
  save                NEVER
  target              SOMETIMES

  Initialization, with an = on the right of the ::,
  is not allowed with the optional attribute.

***parameter
PARAMETER

An object with the parameter attribute is constant.  It is
given an intial value and is not allowed to be given a new
value.

Beginner note: You may write many procedures without ever
specifying the parameter attribute.  If you are creating a
container, however, that you know will always have a
specific value, it is good documentation to make the
"always has this value" container a parameter.  Good
documentation means that you are supplying information
for the reader of your code.

EXAMPLES
--------

 integer, parameter :: SEATS_ACROSS = 50, SEATS_DEEP = 100
 real,    parameter :: PI = 3.1415
 character(len=*), parameter :: DEFAULT_NAME = "Jane Doe"

LOCATION
--------

 YES  1. In a program.
 YES  2. In a module and above the CONTAINS stmt, if any.
 YES  3. In a module, below the CONTAINS stmt, and
         in a procedure.
  NO  4. In a defined type.

 Specifically: Any declaration outside a type definition
 can have PARAMETER subject to the below table.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         NEVER
  dimension           SOMETIMES
  intent              NEVER 
  optional            NEVER
  parameter           
  pointer             NEVER
  private             SOMETIMES
  public              SOMETIMES
  save                NEVER
  target              NEVER

  Initialization, with an = on the right of the ::,
  is required with the parameter attribute.

***pointer
POINTER

An object with the pointer attribute is allowed to "point"
to another object that is either a TARGET or another
POINTER.  Once the association is made between a pointer
and its target, using the => statement, the pointer can be
used to reference the target.

Beginner note: Sometimes you may want to maintain a list
of things and the list often requires modification.  For
example, you may write cook books and often need to throw
away old recipes and add new ones.  Another example, you
may own a baseball card shop that buys and sells cards
every day.

Pointers are not only helpful in programs that require
adding or deleting from a list, but also in programs that
desire many lists of the same data.  For example, say you
want to list your recipes
 alphabetically,
 by date you first tried it,
 by date you most recently tried it,
 by food category, or
 by number of people it serves.
Only one copy of each recipe is required as each of these
five lists can be maintained with pointers

EXAMPLES
--------

 type, public :: recipe
    character(len=40) :: name
    integer :: date_initial, date_recent
    integer :: food_category
    integer :: serving_size
    type(recipe), pointer :: next_recipe
    type(recipe), pointer :: next_date_initial
    type(recipe), pointer :: next_date_recent
 endtype recipe
 type (recipe), pointer :: head_recipe
 type (recipe), pointer :: head_date_initial
 type (recipe), pointer :: head_date_recent
 type(bball), pointer, dimension(:,:) :: nl_cards
 integer, pointer, dimension(:) :: recent_phone_numbers

LOCATION
--------

 YES  1. In a program.
 YES  2. In a module and above the CONTAINS stmt, if any.
 YES  3. In a module, below the CONTAINS stmt, and
         in a procedure.
 YES  4. In a defined type.

 Specifically: Any declaration can have POINTER
 subject to the below attribute compatibility.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         NEVER
  dimension           SOMETIMES
  intent              NEVER
  optional            SOMETIMES
  parameter           NEVER
  pointer
  private             SOMETIMES
  public              SOMETIMES
  save                SOMETIMES
  target              NEVER

  Initialization, with an = on the right of the ::,
  is NEVER allowed with the pointer attribute.

***private
PRIVATE

An object with the private attribute can be seen only
inside its module.  Any module or program that uses a
module is able to see the public items of that module and
is not able to see the private items of that module.

Every item declared in a module above the CONTAINS
statement must be either PRIVATE or PUBLIC.  A module
procedure is given its visibility on a PRIVATE or PUBLIC
statement.  A module defined type or container is given
its visibility with a private or public attribute on its
TYPE, INTEGER, REAL, COMPLEX, CHARACTER, or LOGICAL
statement.

Beginner note: A defined type that is PUBLIC can hide its
components by making them private with a PRIVATE statement
inside the defined type definition (see example.)

EXAMPLES
--------
 public :: GetTotalAmountPaidToCooks, ListCooks
 type, public ::t_cook
  private
    type(person) :: cook
    integer      :: money_paid_for_recipes
 endtype t_cook
 integer, private, parameter :: MAX_COOKS = 100
 type(t_cook), private, dimension(MAX_COOKS) :: cooks
 integer, private :: num_of_cooks_paid
 real, private :: average_amount_per_recipe

LOCATION
--------

  NO  1. In a program.
 YES  2. In a module and above the CONTAINS stmt, if any.
  NO  3. In a module, below the CONTAINS stmt, and
         in a procedure.
  NO  4. In a defined type.

 Specifically: Only module items, those declared above
 the CONTAINS statement, if any, have either PRIVATE or
 PUBLIC, and module items must have either PRIVATE or
 PUBLIC.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         SOMETIMES
  dimension           SOMETIMES
  intent              NEVER
  optional            NEVER
  parameter           SOMETIMES
  pointer             SOMETIMES
  private             
  public              NEVER
  save                SOMETIMES
  target              SOMETIMES

  Initialization, with an = on the right of the ::,
  is allowed with the private attribute.

***public
PUBLIC

An object with the public attribute can be seen in its
module as well as by users of its module.

Every item declared in a module above the CONTAINS
statement must be either PUBLIC or PRIVATE.  A module
procedure is given its visibility on a PUBLIC or PRIVATE
statement.  A module defined type or container is given
its visibility with a public or private attribute on its
TYPE, INTEGER, REAL, COMPLEX, CHARACTER, or LOGICAL
statement.

EXAMPLES
--------
 public :: GetTotalAmountPaidToCooks, ListCooks
 type, public ::t_cook
  private
    type(person) :: cook
    integer      :: money_paid_for_recipes
 endtype t_cook
 integer, public :: total_num_of_recipes
 type(t_cook), public, pointer :: head_of_cook_list
 character(len=30), public :: current_book_title

LOCATION
--------

  NO  1. In a program.
 YES  2. In a module and above the CONTAINS stmt, if any.
  NO  3. In a module, below the CONTAINS stmt, and
         in a procedure.
  NO  4. In a defined type.

 Specifically: Only module items, those declared above
 the CONTAINS statement, if any, have either PUBLIC or
 PRIVATE, and module items must have either PUBLIC or
 PRIVATE.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         SOMETIMES
  dimension           SOMETIMES
  intent              NEVER
  optional            NEVER
  parameter           SOMETIMES
  pointer             SOMETIMES
  private             NEVER
  public              
  save                SOMETIMES
  target              SOMETIMES

  Initialization, with an = on the right of the ::,
  is allowed with the public attribute.

***save
SAVE

An object with the save attribute will have its value
saved if either
 (a) a procedure is finished and then called again, or
 (b) a module is no longer available and then becomes
     available again.
Without the save attribute,
 (a) a container that is local to a procedure, or
 (b) a container declared above the CONTAINS statement,
     if any, in a module
will have an undefined value whenever it becomes visible.

Beginner note: A local variable in a recursive procedure
often has the save attribute so that recursively going
into and coming out of the procedure does not affect its
value.  Another example of a popular use of a saved
container is a counter of the number of times that a
procedure has been called.

EXAMPLES
--------

 real, public, save :: saved_module_item
 integer, save :: num_of_times_called = 0

LOCATION
--------

  NO  1. In a program.
 YES  2. In a module and above the CONTAINS stmt, if any.
 YES  3. In a module, below the CONTAINS stmt, and
         in a procedure.
  NO  4. In a defined type.

 Specifically: Any module declaration can have SAVE
 subject to the below attribute compatibility.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         SOMETIMES
  dimension           SOMETIMES
  intent              NEVER
  optional            NEVER
  parameter           NEVER
  pointer             SOMETIMES
  private             SOMETIMES
  public              SOMETIMES
  save                
  target              SOMETIMES

  Initialization, with an = on the right of the ::,
  is required with the save attribute below the CONTAINS
  statement and is allowed with the save attribute above
  the CONTAINS statement, if any.

***target
TARGET

An object with the target attribute is allowed to be
pointed to by a POINTER.  If the target attribute is not
specified for an object, it may not be pointed to unless
it has the pointer attribute.  The type of the target must
match the type of the pointer.

EXAMPLES
--------

 type(bball), target, dimension(:) :: favorite_cards
 integer, target, dimension(:,:) :: computer_lab_seating

LOCATION
--------

 YES  1. In a program.
 YES  2. In a module and above the CONTAINS stmt, if any.
 YES  3. In a module, below the CONTAINS stmt, and
         in a procedure.
  NO  4. In a defined type.

 Specifically: Any declaration outside a type definition
 can have TARGET subject to the below table.
 
COMPATIBILITY WITH OTHER ATTRIBUTES
-----------------------------------
  ATTR          ALWAYS, NEVER, SOMETIMES
  -----------   ------------------------
  allocatable         SOMETIMES
  dimension           SOMETIMES
  intent              SOMETIMES
  optional            SOMETIMES
  parameter           NEVER
  pointer             NEVER
  private             SOMETIMES
  public              SOMETIMES
  save                SOMETIMES
  target

  Initialization, with an = on the right of the ::,
  is allowed with the target attribute.
***END
