PONY λ M2 Modula-2

Fortran.CodeCompared.To/Pascal

An interactive executable cheatsheet comparing Fortran and Pascal

Fortran 2018 (GCC 15.2) Free Pascal 3.2.2
Program Structure
Hello, World
program hello implicit none print *, "Hello, World!" end program hello
program HelloWorld; begin writeln('Hello, World!'); end.
Fortran opens with program name and closes with end program name. Pascal opens with program Name; and closes with a lone end. — the trailing period, not a repeated name, marks the end of the whole program. writeln is Pascal's direct equivalent of Fortran's print *,.
Comments
program comments_demo implicit none ! This is a full-line comment integer :: total ! This is a trailing comment total = 10 print *, total end program comments_demo
program CommentsDemo; var total: Integer; begin { This is a full-line comment } total := 10; { This is a trailing comment } writeln(total); end.
Fortran comments use ! and run to the end of the line. Pascal comments are bracketed with { ... } (or, equivalently, (* ... *)) and can span multiple lines, unlike Fortran's single-line-only comment marker.
Declarations Section vs. VAR Block
program declarations_demo implicit none integer :: score real :: average score = 95 average = 88.5 print *, "Score:", score print *, "Average:", average end program declarations_demo
program DeclarationsDemo; var score: Integer; average: Double; begin score := 95; average := 88.5; writeln('Score: ', score); writeln('Average: ', average:0:1); end.
Both languages separate declarations from executable code, but the shape differs: Fortran interleaves integer ::/real :: declarations directly after implicit none, one type keyword per line (or per group). Pascal collects every declaration under a single var keyword, one name-and-type pair per line, all before the begin that starts the executable section.
CONTAINS vs. Procedures Declared Before the Main Block
program contains_demo implicit none call greet() contains subroutine greet() print *, "Hello!" end subroutine greet end program contains_demo
program ContainsDemo; procedure Greet; begin writeln('Hello!'); end; begin Greet; end.
Fortran places internal subprograms after the main body, introduced by contains. Pascal is the mirror image: every procedure or function must be fully declared before the main begin...end. block that uses it, since Pascal compiles top-to-bottom in a single pass and has no forward-reference mechanism for ordinary procedures.
Both Languages Are Case-Insensitive
program case_demo implicit none integer :: Total Total = 10 print *, total print *, TOTAL end program case_demo
program CaseDemo; var Total: Integer; begin Total := 10; writeln(total); writeln(TOTAL); end.
A rare point of agreement: both Fortran and Pascal treat identifiers and reserved words as case-insensitive, so Total, total, and TOTAL all refer to the same variable in both languages. Convention in both is to pick one casing per identifier and use it consistently — the compiler does not enforce it.
Data Types
INTEGER vs. Sized Integer Types
program integer_demo use iso_fortran_env, only: int64 implicit none integer :: normal_number integer(kind=int64) :: large_number normal_number = 2147483647 large_number = 9000000000_int64 print *, "Normal:", normal_number print *, "Large:", large_number end program integer_demo
program IntegerTypes; var normalNumber: Integer; { 32-bit on most platforms } largeNumber: Int64; { 64-bit } begin normalNumber := 2147483647; largeNumber := 9000000000; writeln('Normal: ', normalNumber); writeln('Large: ', largeNumber); end.
Fortran controls integer width through the KIND system (integer(kind=int64)). Pascal instead offers a family of differently-named types for each width — ShortInt (8-bit), SmallInt (16-bit), Integer (32-bit), Int64 (64-bit) — chosen by picking the type name directly rather than parameterizing one generic integer keyword.
REAL/DOUBLE PRECISION vs. Single/Double
program real_demo implicit none real :: single_value double precision :: double_value single_value = 3.14159 double_value = 3.14159265358979d0 print *, "Single:", single_value print *, "Double:", double_value end program real_demo
program RealTypes; var singleValue: Single; { 32-bit } doubleValue: Double; { 64-bit — the everyday floating-point type } begin singleValue := 3.14159; doubleValue := 3.14159265358979; writeln('Single: ', singleValue:0:5); writeln('Double: ', doubleValue:0:14); end.
Fortran's real and double precision map directly onto Pascal's Single and Double — both languages give the programmer explicit 32-bit and 64-bit binary floating-point types with no default-precision ambiguity. Both are IEEE 754 under the hood, so both carry the same binary rounding error for values like 0.1.
LOGICAL vs. Boolean
program logical_demo implicit none logical :: is_ready is_ready = .true. if (is_ready) then print *, "Ready" end if end program logical_demo
program BooleanDemo; var isReady: Boolean; begin isReady := True; if isReady then writeln('Ready'); end.
Fortran's logical literals are .true./.false., surrounded by dots. Pascal's Boolean literals are the bare words True/False, capitalized by convention but not required to be (Pascal is case-insensitive). Both are genuine boolean types, unlike COBOL, which has none at all.
A Single CHARACTER vs. Char
program char_demo implicit none character(len=1) :: grade grade = "A" print *, "Grade:", grade end program char_demo
program CharDemo; var grade: Char; begin grade := 'A'; writeln('Grade: ', grade); end.
A single character is character(len=1) in Fortran (a 1-element string, since Fortran has no separate character-vs-string distinction) and Char in Pascal (a genuinely distinct type from string). Both use single quotes for character/string literals.
CHARACTER(len=n) vs. Dynamic String
program fixed_string_demo implicit none character(len=10) :: name name = "Alice" print *, "Name: [", trim(name), "]" print *, "Declared length:", len(name) end program fixed_string_demo
program DynamicStringDemo; var name: string; begin name := 'Alice'; writeln('Name: [', name, ']'); writeln('Current length: ', Length(name)); name := name + ' Smith'; writeln('After append: ', name, ' (length ', Length(name), ')'); end.
Fortran's character(len=10) is a fixed-width, blank-padded field — its length never changes, and appending text beyond 10 characters truncates. Pascal's string type is dynamically sized: appending text grows it automatically, with no declared maximum and no padding at all. This is a role reversal worth noting, since Pascal is otherwise the more manual, lower-level language of the two.
Variables & Constants
Assignment (=) vs. Assignment (:=)
program assignment_demo implicit none integer :: count count = 5 count = count + 1 print *, count end program assignment_demo
program AssignmentDemo; var count: Integer; begin count := 5; count := count + 1; writeln(count); end.
Fortran uses a bare = for assignment, the same symbol used for equality comparisons in an if. Pascal uses the two-character := for assignment specifically, reserving bare = exclusively for equality comparison — so count = 5 would be a comparison expression in Pascal, not an assignment, and would not even compile as a standalone statement.
PARAMETER vs. Const
program parameter_demo implicit none real, parameter :: pi = 3.14159265358979 real, parameter :: gravity = 9.81 print *, "Pi:", pi print *, "Gravity:", gravity end program parameter_demo
program ConstDemo; const Pi = 3.14159265358979; Gravity = 9.81; begin writeln('Pi: ', Pi:0:11); writeln('Gravity: ', Gravity:0:2); end.
Fortran's real, parameter :: and Pascal's const block both declare true compile-time constants that the compiler rejects any attempt to reassign — a direct, one-to-one mapping. Pascal collects all constants under one const keyword the same way var collects variables.
Declaring Several Variables at Once
program multiple_demo implicit none integer :: first_number, second_number, third_number first_number = 1 second_number = 2 third_number = 3 print *, first_number, second_number, third_number end program multiple_demo
program MultipleDemo; var firstNumber, secondNumber, thirdNumber: Integer; begin firstNumber := 1; secondNumber := 2; thirdNumber := 3; writeln(firstNumber, ' ', secondNumber, ' ', thirdNumber); end.
Both languages let a comma-separated list of names share one type declaration: Fortran's integer :: a, b, c and Pascal's a, b, c: Integer read almost identically, just with the type on opposite sides of the name list.
Arithmetic
Integer Division & MOD
program division_demo implicit none integer :: numerator, denominator, quotient, remainder_value numerator = 17 denominator = 5 quotient = numerator / denominator remainder_value = mod(numerator, denominator) print *, "Quotient:", quotient print *, "Remainder:", remainder_value end program division_demo
program DivisionDemo; var numerator, denominator, quotient, remainderValue: Integer; begin numerator := 17; denominator := 5; quotient := numerator div denominator; remainderValue := numerator mod denominator; writeln('Quotient: ', quotient); writeln('Remainder: ', remainderValue); end.
Fortran overloads / for both integer and real division, inferring integer division from operand types. Pascal keeps them syntactically distinct: div is always integer division (a dedicated keyword, not the / symbol, which is reserved for real division and would return a Double even given two integers), and mod is the remainder operator in both languages with the same spelling.
⚠ ** Operator vs. Power Function
program exponent_demo implicit none real :: result_value result_value = 2.0 ** 10 print *, "2^10 =", result_value end program exponent_demo
program ExponentDemo; uses Math; var resultValue: Double; begin resultValue := Power(2.0, 10); writeln('2^10 = ', resultValue:0:1); end.
Fortran has a dedicated ** exponentiation operator built into the language. Pascal has no exponentiation operator at all — raising a number to a power always goes through the Power function from the Math unit. This is a genuine syntax trap for a Fortran programmer: writing 2 ** 10 in Pascal is simply a compile error, not an unexpected result.
Math Intrinsics vs. the Math Unit
program math_intrinsics_demo implicit none print *, "sqrt(144):", sqrt(144.0) print *, "abs(-42):", abs(-42) print *, "sin(0.0):", sin(0.0) end program math_intrinsics_demo
program MathUnitDemo; uses Math; begin writeln('sqrt(144): ', Sqrt(144.0):0:1); writeln('abs(-42): ', Abs(-42)); writeln('sin(0.0): ', Sin(0.0):0:1); end.
sqrt, abs, and the trigonometric functions are intrinsic in Fortran — always available with no import. Pascal requires uses Math; for Sqrt, Sin, Cos, and friends, though Abs, Round, and Trunc live in the always-available System unit. A Fortran programmer's reflex of never needing an import for basic math needs adjusting for Pascal.
MIN/MAX Intrinsics vs. Math Unit Functions
program min_max_demo implicit none integer :: score_a, score_b score_a = 88 score_b = 95 print *, "Highest:", max(score_a, score_b) print *, "Lowest:", min(score_a, score_b) end program min_max_demo
program MinMaxDemo; uses Math; var scoreA, scoreB: Integer; begin scoreA := 88; scoreB := 95; writeln('Highest: ', Max(scoreA, scoreB)); writeln('Lowest: ', Min(scoreA, scoreB)); end.
Fortran's max()/min() intrinsics are always available and accept two or more arguments directly. Pascal's Max/Min live in the Math unit and only accept exactly two arguments — comparing three or more values means nesting calls, Max(a, Max(b, c)), rather than a single flat call.
NINT/INT vs. Round/Trunc
program rounding_demo implicit none real :: value value = 3.7 print *, "nint:", nint(value) print *, "int (truncate):", int(value) print *, "floor:", floor(value) print *, "ceiling:", ceiling(value) end program rounding_demo
program RoundingDemo; uses Math; var value: Double; begin value := 3.7; writeln('Round: ', Round(value)); writeln('Trunc (truncate): ', Trunc(value)); writeln('Floor: ', Floor(value)); writeln('Ceil: ', Ceil(value)); end.
Fortran's nint() (nearest integer), int() (truncate toward zero), floor(), and ceiling() map directly onto Pascal's Round, Trunc, Floor, and Ceil — same four operations, same semantics, just different names for the first two.
Strings
String Concatenation (//) vs. (+)
program concat_demo implicit none character(len=20) :: first_name, last_name character(len=41) :: full_name first_name = "Alice" last_name = "Smith" full_name = trim(first_name) // " " // trim(last_name) print *, trim(full_name) end program concat_demo
program ConcatDemo; var firstName, lastName, fullName: string; begin firstName := 'Alice'; lastName := 'Smith'; fullName := firstName + ' ' + lastName; writeln(fullName); end.
Fortran concatenates with the dedicated // operator. Pascal reuses the ordinary + arithmetic operator for string concatenation — the compiler decides its meaning from the operand types. Because Pascal strings are dynamically sized, no trim()-equivalent padding cleanup is needed the way it is with Fortran's fixed-width fields.
LEN_TRIM vs. Length
program length_demo implicit none character(len=20) :: greeting greeting = "Hello" print *, "Trimmed length:", len_trim(greeting) end program length_demo
program LengthDemo; var greeting: string; begin greeting := 'Hello'; writeln('Length: ', Length(greeting)); end.
Fortran needs two different length functions: len() for the declared field width and len_trim() for the length ignoring trailing padding. Pascal needs only one — Length — because a dynamic string has no padding to ignore in the first place; its length is always exactly the number of characters it currently holds.
Substring Slicing vs. Copy
program substring_demo implicit none character(len=11) :: phrase phrase = "Hello World" print *, phrase(1:5) print *, phrase(7:11) end program substring_demo
program SubstringDemo; var phrase: string; begin phrase := 'Hello World'; writeln(Copy(phrase, 1, 5)); writeln(Copy(phrase, 7, 5)); end.
Fortran's substring syntax phrase(1:5) takes a start and an end position, both inclusive, directly in the variable's own indexing brackets. Pascal has no bracket-based slicing at all — extracting a substring always goes through the Copy(string, startPosition, count) function, whose third argument is a character count, not an end position.
INDEX Intrinsic vs. Pos Function
program search_demo implicit none character(len=30) :: sentence integer :: position sentence = "the quick brown fox" position = index(sentence, "brown") print *, "Found at position:", position end program search_demo
program SearchDemo; var sentence: string; position: Integer; begin sentence := 'the quick brown fox'; position := Pos('brown', sentence); writeln('Found at position: ', position); end.
Fortran's index(haystack, needle) and Pascal's Pos(needle, haystack) both return the 1-based starting position of a substring (0 if not found) — functionally identical, but note the argument order is reversed: Fortran takes the string being searched first, Pascal takes the substring being searched for first.
Case Conversion
program case_convert_demo implicit none character(len=10) :: name integer :: i, code name = "alice" do i = 1, len(name) code = iachar(name(i:i)) if (code >= iachar('a') .and. code <= iachar('z')) then name(i:i) = achar(code - 32) end if end do print *, trim(name) end program case_convert_demo
program CaseConvertDemo; uses SysUtils; var name: string; begin name := 'alice'; writeln(UpperCase(name)); end.
Fortran has no built-in case-conversion intrinsic — converting case means writing a loop over character codes by hand with iachar()/achar(). Pascal's SysUtils unit provides UpperCase and LowerCase directly, a case where Pascal's standard library is considerably more convenient than Fortran's for a common text operation.
Arrays
Array Declaration with Explicit Bounds
program array_declaration_demo implicit none integer :: scores(1:5) scores(1) = 85 scores(2) = 92 scores(5) = 78 print *, scores(1) print *, scores(5) end program array_declaration_demo
program ArrayDeclarationDemo; var scores: array[1..5] of Integer; begin scores[1] := 85; scores[2] := 92; scores[5] := 78; writeln(scores[1]); writeln(scores[5]); end.
Both languages let the programmer choose arbitrary array bounds rather than being locked to 0-based indexing: Fortran's scores(1:5) and Pascal's array[1..5] both declare a 5-element array indexed 1 through 5. Either language could just as easily declare (0:4) or [0..4] — the bounds are a choice, not a language default, in both cases.
⚠ Whole-Array Arithmetic vs. Element-by-Element Loops
program whole_array_demo implicit none real :: prices(3) prices = [10.0, 20.0, 30.0] prices = prices * 0.9 ! scale every element at once print *, prices end program whole_array_demo
program ElementLoopDemo; var prices: array[1..3] of Double; i: Integer; begin prices[1] := 10.0; prices[2] := 20.0; prices[3] := 30.0; for i := 1 to 3 do prices[i] := prices[i] * 0.9; for i := 1 to 3 do write(prices[i]:0:2, ' '); writeln; end.
This is the headline structural difference between these two otherwise-similar languages. Fortran treats an array as a value you can operate on directly: prices = prices * 0.9 multiplies every element in a single statement, with no loop at all. Pascal, like C, has no whole-array operators whatsoever — scaling every element always requires an explicit for loop written out by hand, even though the two languages agree on almost everything else about arrays (bounds, declaration style, 1-based-by-choice indexing).
SUM Intrinsic vs. Manual Accumulation
program array_sum_demo implicit none integer :: numbers(5), total numbers = [10, 20, 30, 40, 50] total = sum(numbers) print *, "Total:", total end program array_sum_demo
program ArraySumDemo; var numbers: array[1..5] of Integer; i, total: Integer; begin numbers[1] := 10; numbers[2] := 20; numbers[3] := 30; numbers[4] := 40; numbers[5] := 50; total := 0; for i := 1 to 5 do total := total + numbers[i]; writeln('Total: ', total); end.
Fortran's sum() intrinsic totals an entire array in a single call. Pascal has no equivalent built-in for a plain static array — the standard idiom is a for loop that adds each element into an accumulator initialized to zero, one more consequence of Pascal's lack of whole-array operations.
Two-Dimensional Arrays
program two_d_demo implicit none integer :: matrix(3, 3) integer :: row, col do row = 1, 3 do col = 1, 3 matrix(row, col) = 0 end do end do matrix(2, 2) = 5 print *, matrix(2, 2) end program two_d_demo
program TwoDDemo; var matrix: array[1..3, 1..3] of Integer; row, col: Integer; begin for row := 1 to 3 do for col := 1 to 3 do matrix[row, col] := 0; matrix[2, 2] := 5; writeln(matrix[2, 2]); end.
Fortran and Pascal both index a 2D array with comma-separated subscripts in one set of parentheses/brackets — matrix(row, col) versus matrix[row, col] — an almost identical shape. Pascal's declaration array[1..3, 1..3] of Integer similarly parallels Fortran's integer :: matrix(3, 3), just with the dimension bounds spelled out explicitly rather than inferred as starting at 1.
ALLOCATABLE Arrays vs. Dynamic Arrays
program allocatable_demo implicit none integer, allocatable :: items(:) integer :: item_count, i item_count = 3 allocate(items(item_count)) items = [100, 200, 300] do i = 1, item_count print *, items(i) end do deallocate(items) end program allocatable_demo
program DynamicArrayDemo; var items: array of Integer; i: Integer; begin SetLength(items, 3); items[0] := 100; items[1] := 200; items[2] := 300; for i := 0 to High(items) do writeln(items[i]); end.
Fortran's allocatable arrays are sized at runtime with allocate()/deallocate() and keep whatever bounds you give them. Pascal's dynamic arrays (array of Integer, no bounds in the declaration) are sized with SetLength and are always 0-indexed regardless of how a same-named static array might have been indexed elsewhere — a subtle trap, since Pascal static arrays commonly start at 1 but dynamic arrays never do.
Control Flow
IF / ELSE IF vs. IF / ELSE
program if_demo implicit none integer :: score score = 85 if (score >= 90) then print *, "Grade: A" else if (score >= 80) then print *, "Grade: B" else print *, "Grade: C or below" end if end program if_demo
program IfDemo; var score: Integer; begin score := 85; if score >= 90 then writeln('Grade: A') else if score >= 80 then writeln('Grade: B') else writeln('Grade: C or below'); end.
Both languages support a flat multi-branch chain, but Pascal has no dedicated else if keyword — else if is simply an else clause whose body happens to be another if statement, which reads identically to a real elseif because Pascal statements need no begin/end wrapper when there is only one statement in a branch. Note also that Pascal never places a semicolon before an else — a semicolon there would terminate the if statement early and leave a dangling else with no matching if.
SELECT CASE vs. CASE OF
program select_case_demo implicit none integer :: day_number day_number = 3 select case (day_number) case (1) print *, "Monday" case (2) print *, "Tuesday" case (3) print *, "Wednesday" case (4, 5) print *, "Thursday or Friday" case default print *, "Weekend" end select end program select_case_demo
program CaseOfDemo; var dayNumber: Integer; begin dayNumber := 3; case dayNumber of 1: writeln('Monday'); 2: writeln('Tuesday'); 3: writeln('Wednesday'); 4, 5: writeln('Thursday or Friday'); else writeln('Weekend'); end; end.
Fortran's select case/case/case default and Pascal's case...of/numbered branches/else are nearly interchangeable — both allow comma-separated value lists on one branch (case (4, 5) versus 4, 5:), and neither falls through to the next branch the way C's switch does.
CASE Ranges
program case_ranges_demo implicit none integer :: score score = 85 select case (score) case (90:100) print *, "A" case (80:89) print *, "B" case default print *, "C or below" end select end program case_ranges_demo
program CaseRangesDemo; var score: Integer; begin score := 85; case score of 90..100: writeln('A'); 80..89: writeln('B'); else writeln('C or below'); end; end.
Fortran writes a case range as lower:upper inside the parentheses. Pascal writes the same range as lower..upper — the same double-dot syntax Pascal already uses for array bounds (array[1..5]), so the two uses of .. reinforce each other once learned.
.AND./.OR. vs. and/or
program logical_ops_demo implicit none logical :: is_weekday, is_holiday is_weekday = .true. is_holiday = .false. if (is_weekday .and. .not. is_holiday) then print *, "Office is open" end if end program logical_ops_demo
program LogicalOpsDemo; var isWeekday, isHoliday: Boolean; begin isWeekday := True; isHoliday := False; if isWeekday and not isHoliday then writeln('Office is open'); end.
Fortran surrounds its logical operators with dots (.and., .or., .not.); Pascal spells the same operators as bare lowercase words (and, or, not) with no punctuation at all — otherwise the logic reads almost identically between the two languages.
Loops
DO Loop vs. FOR/TO
program do_loop_demo implicit none integer :: i do i = 1, 5 print *, "Iteration:", i end do end program do_loop_demo
program ForToDemo; var i: Integer; begin for i := 1 to 5 do writeln('Iteration: ', i); end.
Fortran's do i = 1, 5 and Pascal's for i := 1 to 5 do are functionally identical: both count an explicit loop variable upward through an inclusive range with a step of 1, with the variable available and readable inside the loop body in both languages.
Negative-Step DO vs. FOR/DOWNTO
program countdown_demo implicit none integer :: i do i = 5, 1, -1 print *, i end do end program countdown_demo
program DowntoDemo; var i: Integer; begin for i := 5 downto 1 do writeln(i); end.
Fortran counts downward by giving do a negative step: do i = 5, 1, -1. Pascal has a dedicated keyword for the same purpose — for i := 5 downto 1 do — with no explicit step argument at all, since downto always steps by exactly 1 in the negative direction.
DO WHILE vs. WHILE/DO
program do_while_demo implicit none integer :: balance balance = 1000 do while (balance > 0) balance = balance - 300 print *, "Balance:", balance end do end program do_while_demo
program WhileDemo; var balance: Integer; begin balance := 1000; while balance > 0 do begin balance := balance - 300; writeln('Balance: ', balance); end; end.
Fortran's do while (condition) and Pascal's while condition do both test the condition before each iteration and may run zero times — identical semantics, with Pascal needing a begin...end wrapper only because its loop body here has more than one statement.
REPEAT/UNTIL Has No Fortran Equivalent
program simulated_repeat_demo implicit none integer :: counter logical :: keep_going counter = 1 keep_going = .true. do while (keep_going) print *, counter counter = counter + 1 if (counter > 5) keep_going = .false. end do end program simulated_repeat_demo
program RepeatUntilDemo; var counter: Integer; begin counter := 1; repeat writeln(counter); counter := counter + 1; until counter > 5; end.
Pascal's repeat...until condition tests its condition after the loop body, guaranteeing at least one execution, and continues until the condition becomes true (the opposite sense of while). Fortran has no direct equivalent — a Fortran programmer must simulate a post-tested loop with a do while and a manually managed flag, as shown here, or an infinite do with an if/exit at the bottom.
EXIT/CYCLE vs. Break/Continue
program exit_cycle_demo implicit none integer :: i do i = 1, 10 if (mod(i, 2) == 0) cycle if (i > 7) exit print *, i end do end program exit_cycle_demo
program BreakContinueDemo; var i: Integer; begin for i := 1 to 10 do begin if i mod 2 = 0 then continue; if i > 7 then break; writeln(i); end; end.
Fortran's cycle (skip to next iteration) and exit (break out of the loop) map directly onto Pascal's continue and break — nearly identical vocabulary between the two languages, unlike COBOL, which has neither.
Procedures & Functions
SUBROUTINE vs. Procedure
program subroutine_demo implicit none call greet("Alice") call greet("Bob") contains subroutine greet(person_name) character(len=*), intent(in) :: person_name print *, "Hello, " // trim(person_name) // "!" end subroutine greet end program subroutine_demo
program ProcedureDemo; procedure Greet(const personName: string); begin writeln('Hello, ', personName, '!'); end; begin Greet('Alice'); Greet('Bob'); end.
A Fortran subroutine is called with the call keyword; a Pascal procedure is called by name alone, with no equivalent keyword required. Both describe a callable unit that performs an action and returns no value — the direct structural counterpart of each other, unlike COBOL, which has no comparable parameterized unit at all outside a full subprogram.
INTENT(IN) vs. Const Parameter
program intent_in_demo implicit none call display_info("Alice", 95) contains subroutine display_info(person_name, score) character(len=*), intent(in) :: person_name integer, intent(in) :: score print *, trim(person_name), ": ", score end subroutine display_info end program intent_in_demo
program ConstParamDemo; procedure DisplayInfo(const personName: string; const score: Integer); begin writeln(personName, ': ', score); end; begin DisplayInfo('Alice', 95); end.
Fortran's intent(in) and Pascal's const parameter modifier serve the identical purpose: both tell the compiler the parameter is read-only, and both cause a compile-time error if the procedure tries to assign to it. This is one of the closest one-to-one mappings between the two languages' feature sets.
INTENT(INOUT) vs. Var Parameter
program intent_inout_demo implicit none integer :: first_number, second_number first_number = 1 second_number = 2 call swap(first_number, second_number) print *, first_number, second_number contains subroutine swap(first_value, second_value) integer, intent(inout) :: first_value, second_value integer :: temp_value temp_value = first_value first_value = second_value second_value = temp_value end subroutine swap end program intent_inout_demo
program VarParamDemo; procedure Swap(var firstValue, secondValue: Integer); var tempValue: Integer; begin tempValue := firstValue; firstValue := secondValue; secondValue := tempValue; end; var firstNumber, secondNumber: Integer; begin firstNumber := 1; secondNumber := 2; Swap(firstNumber, secondNumber); writeln(firstNumber, ' ', secondNumber); end.
Fortran's intent(inout) and Pascal's var parameter modifier both pass the caller's actual variable by reference, letting the procedure both read and modify it in place — another near-exact mapping. Pascal additionally has a write-only out parameter mode matching Fortran's intent(out), completing the correspondence across all three of Fortran's intent modes.
FUNCTION vs. Function — Both Usable in Expressions
program function_demo implicit none print *, "Fahrenheit:", to_fahrenheit(100.0) contains function to_fahrenheit(celsius) result(fahrenheit) real, intent(in) :: celsius real :: fahrenheit fahrenheit = celsius * 9.0 / 5.0 + 32.0 end function to_fahrenheit end program function_demo
program FunctionDemo; function ToFahrenheit(celsius: Double): Double; begin ToFahrenheit := celsius * 9.0 / 5.0 + 32.0; end; begin writeln('Fahrenheit: ', ToFahrenheit(100.0):0:1); end.
Unlike COBOL, Pascal has real user-defined functions with return values that can be used directly inside expressions, exactly like Fortran. The return value is set by assigning to the function's own name (ToFahrenheit := ...) — Free Pascal also accepts the more modern Result := ... — rather than Fortran's optional result() clause, but the calling convention is identical: ToFahrenheit(100.0) can be nested inside any expression exactly as to_fahrenheit(100.0) can in Fortran.
Recursive Functions
program recursive_demo implicit none print *, "5! =", factorial(5) contains recursive function factorial(n) result(product_value) integer, intent(in) :: n integer :: product_value if (n <= 1) then product_value = 1 else product_value = n * factorial(n - 1) end if end function factorial end program recursive_demo
program RecursiveDemo; function Factorial(n: Integer): Int64; begin if n <= 1 then Factorial := 1 else Factorial := n * Factorial(n - 1); end; begin writeln('5! = ', Factorial(5)); end.
Fortran requires the explicit recursive keyword before a function or subroutine can call itself — an important safety default, since ordinary Fortran subprograms are not guaranteed reentrant. Pascal has no such keyword: every Pascal function and procedure may call itself freely with no special declaration at all.
RETURN vs. Exit
program early_return_demo implicit none print *, "Absolute value of -5:", absolute_value(-5) print *, "Absolute value of 5:", absolute_value(5) contains function absolute_value(number) result(magnitude) integer, intent(in) :: number integer :: magnitude if (number >= 0) then magnitude = number return end if magnitude = -number end function absolute_value end program early_return_demo
program EarlyReturnDemo; function AbsoluteValue(number: Integer): Integer; begin if number >= 0 then begin AbsoluteValue := number; Exit; end; AbsoluteValue := -number; end; begin writeln('Absolute value of -5: ', AbsoluteValue(-5)); writeln('Absolute value of 5: ', AbsoluteValue(5)); end.
Fortran's return statement exits a subprogram immediately, before reaching its natural end. Pascal's equivalent is the built-in Exit procedure — same purpose, different name, and both languages require the return value to already have been assigned before the early exit statement runs.
Records
Derived Type vs. Record
program derived_type_demo implicit none type :: person character(len=20) :: name integer :: age end type person type(person) :: employee employee = person("Alice", 30) print *, trim(employee%name) print *, employee%age end program derived_type_demo
program RecordDemo; type TPerson = record name: string; age: Integer; end; var employee: TPerson; begin employee.name := 'Alice'; employee.age := 30; writeln(employee.name); writeln(employee.age); end.
A Fortran type and a Pascal record are nearly identical concepts: both group named fields of possibly different types into one value, both are declared once and instantiated many times, and both use a member-access operator to reach a field — % in Fortran, . in Pascal. Pascal record type names are conventionally prefixed with T.
Array of Derived Types vs. Array of Records
program array_of_types_demo implicit none type :: point real :: x real :: y end type point type(point) :: points(2) points(1) = point(1.0, 2.0) points(2) = point(3.0, 4.0) print *, points(1)%x, points(1)%y print *, points(2)%x, points(2)%y end program array_of_types_demo
program ArrayOfRecordsDemo; type TPoint = record x, y: Double; end; var points: array[1..2] of TPoint; begin points[1].x := 1.0; points[1].y := 2.0; points[2].x := 3.0; points[2].y := 4.0; writeln(points[1].x:0:1, ' ', points[1].y:0:1); writeln(points[2].x:0:1, ' ', points[2].y:0:1); end.
Both languages combine arrays and records the same way: an array whose element type is a record/derived type, accessed by combining the subscript and the member operator — points(1)%x versus points[1].x. The shape of the two lines is nearly a character-for-character translation of each other.
Nested Records
program nested_type_demo implicit none type :: address character(len=20) :: city end type address type :: employee_type character(len=20) :: name type(address) :: home_address end type employee_type type(employee_type) :: employee employee%name = "Alice" employee%home_address%city = "Springfield" print *, trim(employee%name) print *, trim(employee%home_address%city) end program nested_type_demo
program NestedRecordDemo; type TAddress = record city: string; end; TEmployee = record name: string; homeAddress: TAddress; end; var employee: TEmployee; begin employee.name := 'Alice'; employee.homeAddress.city := 'Springfield'; writeln(employee.name); writeln(employee.homeAddress.city); end.
A record/derived type can contain another record/derived type as a field in both languages, and the member-access chain reads the same way in both: employee%home_address%city versus employee.homeAddress.city. Pascal declares both nested types in a single type block separated by semicolons; Fortran gives each its own separate type ... end type block.
Units & Modules
MODULE/USE vs. Unit/Uses
program module_use_demo use iso_fortran_env, only: real64 implicit none real(kind=real64) :: value value = 3.14159265358979_real64 print *, value end program module_use_demo
program UnitUsesDemo; uses Math, { trigonometry, Power, floor, ceil } SysUtils; { Format, UpperCase, string utilities } var value: Double; begin value := Pi; writeln(value:0:14); end.
Fortran's use module_name, only: names and Pascal's uses UnitName; both import a library of related declarations — the mechanism a Rubyist would compare to require. Fortran can selectively import only specific names with only:; a plain Pascal uses clause always imports everything a unit exports, with no selective-import syntax.
Internal Files vs. Format Function
program internal_io_demo implicit none character(len=20) :: label_text integer :: year year = 2026 write(label_text, '("Report_", i4, ".txt")') year print *, trim(label_text) end program internal_io_demo
program FormatDemo; uses SysUtils; var labelText: string; year: Integer; begin year := 2026; labelText := Format('Report_%d.txt', [year]); writeln(labelText); end.
Fortran builds a formatted string by writing to a character variable used as an "internal file" — an sprintf-equivalent reached through the ordinary write statement. Pascal reaches the same result through SysUtils's Format function, whose %d-style placeholders and array-of-arguments syntax will look immediately familiar to anyone who has used C's printf.
Output & Formatting
PRINT * vs. Writeln
program print_demo implicit none integer :: count real :: price count = 42 price = 9.99 print *, "Count:", count print *, "Price:", price end program print_demo
program WritelnDemo; var count: Integer; price: Double; begin count := 42; price := 9.99; writeln('Count: ', count); writeln('Price: ', price:0:2); end.
print *, ... in Fortran and writeln(...) in Pascal both write a comma-separated list of values to standard output followed by a newline. Pascal additionally offers write (no trailing newline) for building up a line across several calls — Fortran has no equivalent no-newline print statement in its simple print *, form.
FORMAT Descriptors vs. Field-Width Syntax
program format_demo implicit none real :: amount amount = 1234.5 write(*, '(a, f10.2)') "Amount: ", amount end program format_demo
program FieldWidthDemo; var amount: Double; begin amount := 1234.5; writeln('Amount: ', amount:10:2); end.
Fortran controls output layout with a separate FORMAT descriptor string passed to write, such as f10.2 (fixed-point, 10 characters wide, 2 decimal places). Pascal folds the same information directly into the writeln argument list using colon syntax: amount:10:2 means the same 10-wide, 2-decimal formatting, with no separate format string needed.
Building a Line Without a Trailing Newline
program no_newline_demo implicit none integer :: i do i = 1, 5 write(*, '(i0, a)', advance='no') i, " " end do print *, "" end program no_newline_demo
program NoNewlineDemo; var i: Integer; begin for i := 1 to 5 do write(i, ' '); writeln; end.
Fortran suppresses the trailing newline with advance='no' on a write statement — an unusually verbose piece of syntax for such a common need. Pascal's plain write (as opposed to writeln) never emits a newline at all, so building up a line piece by piece across a loop is simpler in Pascal: call write repeatedly, then call bare writeln once to finish the line.
⚠ Gotchas for Fortran Programmers
⚠ The Semicolon Is a Statement Separator
program semicolon_demo implicit none integer :: value value = 5 print *, "Positive" end program semicolon_demo
program SemicolonDemo; var value: Integer; begin value := 5; writeln('Positive') end.
Fortran statements are terminated by a newline, with nothing equivalent to a required trailing punctuation mark. Pascal semicolons are technically statement separators, not terminators — the last statement before an end does not strictly need one, as shown here. A stray extra semicolon (e.g. right after then) silently creates an empty statement rather than a syntax error, which can make an intended if body execute unconditionally — a subtle bug a Fortran programmer's newline-based intuition will not catch by habit.
⚠ Integer Overflow Wraps Silently in Both Languages
program overflow_demo implicit none integer(kind=1) :: tiny_value tiny_value = 127 tiny_value = tiny_value + 1 print *, tiny_value end program overflow_demo
program OverflowDemo; var tinyValue: ShortInt; { -128..127 } begin tinyValue := 127; tinyValue := tinyValue + 1; writeln(tinyValue); end.
Both languages agree here, unlike Ruby or Python: a fixed-width integer that overflows its range wraps silently to a nonsensical value (127 + 1 becomes -128 in an 8-bit signed field) with no error, no warning, and no exception raised in either Fortran or Pascal. Neither language has an automatically-growing arbitrary-precision integer type as a fallback.
⚠ Dynamic Arrays Are Always 0-Indexed
program static_one_based_demo implicit none integer :: fixed_array(1:5) fixed_array(1) = 100 print *, fixed_array(1) end program static_one_based_demo
program DynamicZeroIndexedDemo; var fixedArray: array[1..5] of Integer; dynamicArray: array of Integer; begin fixedArray[1] := 100; writeln(fixedArray[1]); SetLength(dynamicArray, 5); dynamicArray[0] := 100; { dynamic arrays always start at 0 } writeln(dynamicArray[0]); end.
Fortran arrays default to 1-based indexing but can be declared with any custom bounds, including 0-based, and that choice is consistent everywhere the array is used. Pascal static arrays follow the same "choose your own bounds" rule — but Pascal dynamic arrays (array of Integer, sized with SetLength) are always 0-indexed with no way to change it. Mixing static and dynamic arrays in the same Pascal program means living with two different indexing conventions side by side.
⚠ No Whole-Array Comparisons or Boolean Masks
program where_demo implicit none integer :: numbers(5) logical :: mask(5) numbers = [1, -2, 3, -4, 5] mask = numbers > 0 where (mask) numbers = numbers * 10 end where print *, numbers end program where_demo
program NoWhereDemo; var numbers: array[1..5] of Integer; i: Integer; begin numbers[1] := 1; numbers[2] := -2; numbers[3] := 3; numbers[4] := -4; numbers[5] := 5; for i := 1 to 5 do if numbers[i] > 0 then numbers[i] := numbers[i] * 10; for i := 1 to 5 do write(numbers[i], ' '); writeln; end.
Fortran's where construct applies an operation only to the array elements that satisfy a condition — a whole-array conditional built directly into the language, with the condition itself expressed as a whole-array comparison (numbers > 0 produces a whole array of booleans). Pascal has neither piece: no whole-array comparison operators and no masked-assignment construct, so the equivalent logic always becomes an explicit for loop with an if inside it — one more instance of the whole-array-versus-element-by-element gap that runs through every array-related concept on this page.