# Assumed-Shape Arrays

In many cases, passing the whole extent of an array to a function/subroutine is too tedious (e.g., you have ten arrays with different extents). Sometimes, you don't even know their extents. To overcome this, Fortran 90 offers the so-called assumed-shape arrays. Of course, they must be formal arguments.

### Syntax

To declare an assumed-shape array, follow all rules discussed in previous pages, except its extent. An assumed-shape array has an extent like the following:
```lower-bound :
:
```
• The first form has a lower-bound followed by a colon, while the second has only a colon. Both forms do not have an upper bound. If the lower-bound is 1, it can be omitted and the first form reduces to the second.
• The meaning of shape will be clear later when two dimensional arrays are discussed.
• An assumed-shape formal argument array receives the size of its actual argument and the extent is lost. More precisely, if the actual argument is declared as
```INTEGER, DIMENSION(-3:3) :: x
```
and the corresponding formal argument is declared as
```INTEGER, DIMENSION(2:) :: y
```
then the caller sees array x() as a collection of the following elements:
```x(-3)  x(-2)  x(-1)  x(0)  x(1)  x(2)  x(3)
```
Since the extent is lost when passing to an assumed-shape array, the callee would know array y() has 7 elements as follows:
```y(2)   y(3)   y(4)   y(5)  y(6)  y(7)  y(8)
```
This is simply because the callee has an assumed-shape array with a lower bound 2. As a result, when the callee uses y(2), y(3), ..., y(8), it actually uses x(-3), x(-2), ..., x(3), respectively.
• To address this problem, when the lower bound is not 1, one can pass it from the caller and the callee uses it to declare an assumed-shape array.

Suppose the caller has the following:

```INTEGER, DIMENSION(-3:3) :: x
..........
CALL  SomeOne(x, -3)
```
The callee could declare an assumed-shape array like the following:
```SUBROUTINE  SomeOne(y, LowerBound)
IMPLICIT  NONE
INTEGER, DIMENSION(LowerBound:), INTENT(IN) :: y
..........
END SUBROUTINE  SomeOne
```
In this case, the extent of array y() agrees with that of actual argument array x().

### Examples

Let us redo the examples in the previous page:
• Since an assumed-shape array does not require an upper bound, the call to subroutine First() has only five arguments rather than six. In the declaration of formal argument y, (1:) is used; but you can certainly use (:).
```PROGRAM  Example
IMPLICIT  NONE
INTEGER, PARAMETER :: LOWER_BOUND = 20
INTEGER, PARAMETER :: UPPER_BOUND = 50
INTEGER, DIMENSION(LOWER_BOUND:UPPER_BOUND) :: Data
REAL, DIMENSION(1:LOWER_BOUND)              :: Values
..........
CALL  First(Data, Value, Answers, LOWER_BOUND, 21)
..........
CONTAINS
SUBROUTINE  First(x, y, z, Lower, LL)
IMPLICIT  NONE
INTEGER, INTENT(IN)                    :: Lower
INTEGER, INTENT(IN)                    :: LL
INTEGER, DIMENSION(Lower:), INTENT(IN) :: x
REAL, DIMENSION(1:), INTENT(OUT)       :: y
LOGICAL, DIMENSION(LL:), INTENT(INOUT) :: z
..........
END SUBROUTINE  First
END PROGRAM   Example
```
• In the following example, since the actual argument has a lower bound 1, the corresponding formal argument x() is declared with an extent of (:).
```PROGRAM  Test
IMPLICIT  NONE
INTEGER, PARAMETER :: MAX_SIZE = 1000
REAL, DIMENSION(1:MAX_SIZE) :: Data
INTEGER                     :: ActualSize
INTEGER                     :: i

WRITE(*,*) "Sum = ", Sum(Data, ActualSize)

CONTAINS
REAL FUNCTION  Sum(x, n)
IMPLICIT  NONE
INTEGER, INTENT(IN)            :: n
REAL, DIMENSION(:), INTENT(IN) :: x
REAL                           :: Total
INTEGER                        :: i

Total = 0.0
DO i = 1, n
Total = Total + x(i)
END DO
Sum = Total
END FUNCTION  Sum
END PROGRAM  Test
```

• As mentioned earlier, when using assumed-shape arrays, the actual extent is not passed. Instead, only the number of elements is implicitly passed. If the lower bound of an extent is different from that of the corresponding actual argument, element correspondence will be different. This is why a correct lower bound is important.
• There are three Fortran functions that can be used to retrieve the extent and the size of an array:
• SIZE(x) takes an array and returns the number of elements in x.
• LBOUND(x) takes an array and returns the lower bound of x()'s extent.
• UPPER(x) takes an array and returns the upper bound of x()'s extent.
If an assumed-shape array a() has a correct lower bound, say L, then SIZE(a) returns the number of elements of a() and the upper bound of a() is L+SIZE(a)-1. Therefore, if you insist to have a correct upper bound, you can consider the following trick:
```SUBROUTINE  Example(a, Lower)
IMPLICIT  NONE
INTEGER, DIMENSION(Lower:Lower+SIZE(a)-1), INTENT(INOUT) :: a
..........
END SUBROUTINE
```
• Please take a look at the following example and try to figure out what output would be generated.
```PROGRAM  Bound
IMPLICIT  NONE
INTEGER, DIMENSION(-10:10) :: a
INTEGER, DIMENSION(10:20)  :: b
INTEGER, DIMENSION(1:100)  :: c
INTEGER, DIMENSION(1:40)   :: d

WRITE(*,*) "Array a()'s info:"
CALL  DisplayInfo(a)

WRITE(*,*) "Array b()'s info:"
CALL  DisplayInfo(b)

WRITE(*,*) "Array c()'s info:"
CALL  DisplayInfo(c)

CONTAINS
SUBROUTINE  DisplayInfo(x)
IMPLICIT  NONE
INTEGER, DIMENSION(:), INTENT(IN) :: x

WRITE(*,*) "   Size        = ", SIZE(x)
WRITE(*,*) "   Lower bound = ", LBOUND(x)
WRITE(*,*) "   Upper bound = ", UBOUND(x)
WRITE(*,*)
END SUBROUTINE

END PROGRAM  Bound
```
• The call to DisplayInfo(a) should display 21 for size, 1 for lower bound and 21 for upper bound. The lower bound is 1, because array x() in subroutine DisplayInfo() has 1 as its default.
• The call to DisplayInfo(b) should display 11 for size, 1 for lower bound and 11 for upper bound.
• The call to DisplayInfo(c) should display 100 for size, 1 for lower bound, and 100 for upper bound.