100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Subroutines and Functions

Structuring reusable Fortran code with SUBROUTINEs, FUNCTIONs, INTENT, and pass-by-reference arguments.

Control Flow & ProceduresIntermediate10 min readJul 10, 2026
Analogies

Subroutines and Functions

Fortran splits reusable code into two kinds of procedures: SUBROUTINEs, which perform an action and may modify their arguments but return no value directly, and FUNCTIONs, which compute and return a single value that can be used directly in an expression. Both can be internal (nested inside a PROGRAM or another procedure via CONTAINS), external (compiled separately, historically riskier because the compiler couldn't check argument consistency), or module procedures, which is now the recommended approach because it guarantees compile-time interface checking.

🏏

Cricket analogy: A team's designated 'super sub' fielder who runs on to make one specific play and comes off again is like a SUBROUTINE — invoked to perform an action (a run-out) without handing back a single number, unlike a strike rate calculation, which is more like a FUNCTION returning one value.

Defining and Calling Subroutines

A subroutine is declared with SUBROUTINE name(arg1, arg2, ...) ... END SUBROUTINE and invoked with the CALL statement, e.g., CALL update_position(x, y, dt). Arguments are passed by reference by default (with some compiler-dependent exceptions for expressions), meaning changes the subroutine makes to a dummy argument are reflected in the caller's actual argument, which is how a subroutine can 'return' multiple modified values without a single return value.

🏏

Cricket analogy: Calling CALL bowl_over(bowler_stats, over_number) hands the bowler_stats record to the subroutine by reference, so when it updates wickets and runs conceded inside the routine, the captain's scorecard back in the main program reflects those changes immediately, just like a scorer updating the master sheet in real time.

fortran
MODULE geometry
  IMPLICIT NONE
CONTAINS
  REAL FUNCTION circle_area(radius) RESULT(area)
    REAL, INTENT(IN) :: radius
    area = 3.14159265 * radius**2
  END FUNCTION circle_area

  SUBROUTINE scale_rectangle(width, height, factor)
    REAL, INTENT(INOUT) :: width, height
    REAL, INTENT(IN) :: factor
    width  = width  * factor
    height = height * factor
  END SUBROUTINE scale_rectangle
END MODULE geometry

PROGRAM shapes
  USE geometry
  IMPLICIT NONE
  REAL :: r, w, h, a

  r = 4.0
  a = circle_area(r)
  PRINT *, 'Area = ', a

  w = 10.0
  h = 5.0
  CALL scale_rectangle(w, h, 2.0)
  PRINT *, 'Scaled: ', w, h
END PROGRAM shapes

Functions and Return Values

A function is declared with a type prefix, e.g., REAL FUNCTION compute_area(radius) ... compute_area = 3.14159 * radius**2 ... END FUNCTION, and is invoked directly within an expression, e.g., area = compute_area(5.0). Modern Fortran also allows RESULT(name) to give the return variable an explicit name distinct from the function name, which is required for recursive functions, and functions should generally be declared PURE when they have no side effects, enabling compiler optimizations and safe use inside FORALL and DO CONCURRENT constructs.

🏏

Cricket analogy: REAL FUNCTION strike_rate(runs, balls) RESULT(sr) computes and returns a single number that a commentator plugs directly into a sentence, just as sr = strike_rate(87, 52) is used inline the same way a broadcaster quotes 'a strike rate of 167' without a separate step.

Recursive functions must be declared with the RECURSIVE keyword and typically use RESULT(name) so the return variable has a distinct name from the function itself, e.g., RECURSIVE INTEGER FUNCTION factorial(n) RESULT(f) — without RECURSIVE, calling the function from within itself is a compile-time error.

Argument Passing: INTENT and Pass-by-Reference

Dummy arguments in both subroutines and functions should be declared with an INTENT attribute — INTENT(IN) for read-only inputs, INTENT(OUT) for values the procedure sets but doesn't need to read, and INTENT(INOUT) for values both read and modified — which lets the compiler catch accidental modifications of what should be read-only data and clarifies the procedure's contract for anyone reading the interface. Declaring INTENT is not just documentation: attempting to assign to an INTENT(IN) argument is a compile-time error, unlike languages where argument mutability is enforced only by convention.

🏏

Cricket analogy: Declaring pitch_report as INTENT(IN) in a subroutine that decides team selection is like a selector who reads the pitch conditions but has no authority to alter them, while the chosen_eleven argument marked INTENT(OUT) is exactly what the selector is meant to produce.

Never modify an INTENT(IN) dummy argument inside a procedure — the compiler will reject it, and relying on a function to silently mutate its inputs (instead of using INTENT(OUT/INOUT) explicitly) makes code far harder to reason about and debug in large scientific codebases.

  • SUBROUTINEs perform actions and are invoked with CALL; FUNCTIONs compute and return one value usable directly in an expression.
  • Arguments are passed by reference by default, so subroutines can 'return' multiple modified values through their arguments.
  • Always declare INTENT(IN), INTENT(OUT), or INTENT(INOUT) on dummy arguments — the compiler enforces the contract at compile time.
  • Functions can use RESULT(name) to name the return variable distinctly from the function name; this is required for RECURSIVE functions.
  • PURE functions have no side effects and can be used safely inside FORALL and DO CONCURRENT constructs.
  • Module procedures are preferred over external procedures because the compiler checks argument types and counts against the interface.
  • Attempting to assign to an INTENT(IN) argument is a compile-time error, not just a style violation.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#FortranStudyNotes#SubroutinesAndFunctions#Subroutines#Functions#Defining#Calling#StudyNotes#SkillVeris#ExamPrep