5. Select-Case AND OOP

by gg582 · 2026-05-27 05:15:34 · 36 views

1. Syntax Rules for Modern Fortran

  • Case Insensitivity: Fortran keywords are case-insensitive. Modern coding conventions prefer lowercase for keywords (if, select case).
  • Variable Declarations: Under implicit none, all variables and function result variables must be explicitly typed.

2. Basic and Multi-Way Conditionals

IF Constructs

  • Logical IF: Executes a single statement when the condition is true. No then or end if required.
if (x < 0) x = -x

  • IF Block: Used for multi-line or multi-condition branching.
if (x > 0) then
    print *, "Positive"
else if (x < 0) then
    print *, "Negative"
else
    print *, "Zero"
end if

SELECT CASE Construct

Executes a specific block based on the evaluation of an expression.

  • Supported Data Types: integer, character, logical.
  • Constraint: real (floating-point) types are strictly prohibited due to precision errors.
  • Constraint: The case selector does not accept arrays. It only accepts scalar constants, constant expressions, lists, or ranges.
select case (choice)
case (1)                ! Single scalar constant
    print *, "Option 1"
case (2, 3, 5)          ! List of constants
    print *, "Prime choices"
case (10:20)            ! Range (10 <= choice <= 20)
    print *, "Range match"
case (:9)               ! Lower bounded range (choice <= 9)
    print *, "Single digit"
case (21:)              ! Upper bounded range (choice >= 21)
    print *, "Above 20"
case default            ! Fallback case
    print *, "No match"
end select


3. Legacy and Obsolete Branching (Fortran 2018)

  • Unconditional GO TO: Jumps directly to a statement label. Unsafe and breaks structural integrity.
10  continue
    ! processing
    if (condition) go to 10

  • Arithmetic IF (Obsolete): Branches to three different labels depending on whether the expression is negative, zero, or positive.
if (x - y) 10, 20, 30  ! <0: label 10, ==0: label 20, >0: label 30

  • Computed GO TO (Obsolete): Jumps to a label in a list based on an integer value. Replaced by select case.
go to (10, 20, 30) i   ! i=1: label 10, i=2: label 20, i=3: label 30

  • Shared Loop Termination (Deleted): Multiple do loops ending on the same statement label are deleted in Fortran 2018. Each loop requires its own end do.

4. Modern Specialized Conditionals

WHERE Construct

Applies a logical mask to execute element-wise array operations without explicit loops.

where (array > 0)
    inverse = 1.0 / array
elsewhere
    inverse = 0.0
end where

SELECT RANK (Fortran 2018+)

Branches based on the rank (number of dimensions) of an assumed-rank dummy argument.

select rank (array_arg)
rank (0)
    print *, "Scalar"
rank (1)
    print *, "1D Array"
end select

SELECT TYPE (Fortran 2003+)

Branches based on the dynamic type of a polymorphic entity. It requires the target variable to be a polymorphic class entity (class(*) or class(base_type)). It allows downcasting to access attributes unique to a child extension type.


5. Multi-File Object-Oriented Implementation

To avoid name collisions, the module name must differ from the derived type names inside it.

module/shape/shape.f90

module shape_mod
    implicit none
    private
    public :: shape, circle, rectangle

    ! Parent abstract class
    type, abstract :: shape
    contains
        procedure(get_area_proc), deferred :: get_area
    end type shape

    ! Abstract interface for deferred method
    abstract interface
        function get_area_proc(this) result(area)
            import :: shape
            class(shape), intent(in) :: this
            real :: area
        end function get_area_proc
    end interface

    ! Child class: Circle
    type, extends(shape) :: circle
        real :: radius
    contains
        procedure :: get_area => get_circle_area
    end type circle

    ! Child class: Rectangle
    type, extends(shape) :: rectangle
        real :: width, height
    contains
        procedure :: get_area => get_rect_area
    end type rectangle

contains

    real function get_circle_area(this) result(area)
        class(circle), intent(in) :: this
        area = 3.14159 * this%radius**2
    end function

    real function get_rect_area(this) result(area)
        class(rectangle), intent(in) :: this
        area = this%width * this%height
    end function

end module shape_mod

main.f90

program main
    use shape_mod
    implicit none

    class(shape), allocatable :: my_shape
    integer :: choice

    print *, "select shape type (1: circle, 2: rectangle):"
    read *, choice

    if (choice == 1) then
        allocate(circle :: my_shape)
        select type (s => my_shape)
        type is (circle)
            s%radius = 5.0
        end select
    else if (choice == 2) then
        allocate(rectangle :: my_shape)
        select type (s => my_shape)
        type is (rectangle)
            s%width = 4.0
            s%height = 6.0
        end select
    else
        stop "invalid choice."
    end if

    call print_info(my_shape)

contains

    subroutine print_info(s)
        class(shape), intent(in) :: s

        print *, "--- info ---"
        print *, "calculated area:", s%get_area()

        ! Runtime type verification via select type
        select type (item => s)
        type is (circle)
            print *, "type: circle / radius:", item%radius
        type is (rectangle)
            print *, "type: rectangle / size:", item%width, "x", item%height
        end select
    end subroutine print_info

end program main


6. Build Specification (Makefile)

FC = gfortran
FFLAGS = -I./module/shape
MOD_DIR = module/shape
SRC_MOD = $(MOD_DIR)/shape.f90
SRC_MAIN = main.f90
OBJ_MOD = shape.o
TARGET = main_exe

all: $(TARGET)

$(TARGET): $(OBJ_MOD) $(SRC_MAIN)
    $(FC) $(FFLAGS) $(OBJ_MOD) $(SRC_MAIN) -o $(TARGET)

$(OBJ_MOD): $(SRC_MOD)
    $(FC) -c $(SRC_MOD) -o $(OBJ_MOD)

clean:
    rm -f *.o *.mod $(TARGET)
Back

Comments

No comments yet.