Skip to content

Instantly share code, notes, and snippets.

@alanbriolat
Created July 18, 2012 11:33
Show Gist options
  • Save alanbriolat/3135713 to your computer and use it in GitHub Desktop.
Save alanbriolat/3135713 to your computer and use it in GitHub Desktop.
The many faces of function definition in Fortran 95
fortran_hell.f95:146.12:
j = foo * foo
1
Warning: Possible change of value in conversion from REAL(4) to INTEGER(4) at (1)
program example
real :: x, y
x = 12.0
y = a(x)
print *, "x =", x, "y =", y, "a(x) =", a(x)
x = 12.0
y = b(x)
print *, "x =", x, "y =", y, "b(x) =", b(x)
x = 12.0
y = c(x)
print *, "x =", x, "y =", y, "c(x) =", c(x)
x = 12.0
y = d(x)
print *, "x =", x, "y =", y, "d(x) =", d(x)
x = 12.0
y = e(x)
print *, "x =", x, "y =", y, "e(x) =", e(x)
x = 12.0
y = f(x)
print *, "x =", x, "y =", y, "f(x) =", f(x)
x = 12.0
y = g(x)
print *, "x =", x, "y =", y, "g(x) =", g(x)
x = 12.0
y = h(x)
print *, "x =", x, "y =", y, "h(x) =", h(x)
x = 12.0
y = i(x)
print *, "x =", x, "y =", y, "i(x) =", i(x)
x = 12.0
y = j(x)
print *, "x =", x, "y =", y, "j(x) =", j(x)
x = 12.0
y = k(x)
print *, "x =", x, "y =", y, "k(x) =", k(x)
contains
! These are all the exact same function, and all valid fortran 95 (compiled
! with "gfortran -std=f95 -Wall").
! Minimal definition: implicit types (real), function name used as return
! variable. The roundabout route of calculating the result is to show off
! an unexpected feature that will catch out anybody unaware of it... (See
! below.)
function a(foo)
foo = foo * foo
a = foo
end function
! Made types explicit
function b(foo)
implicit none
real :: b, foo
foo = foo * foo
b = foo
end function
! Moved return type to declaration line
real function c(foo)
implicit none
real :: foo
foo = foo * foo
c = foo
end function
! Add optional function name after "end function"
real function d(foo)
implicit none
real :: foo
foo = foo * foo
d = foo
end function d
! Explicitly named return variable
real function e(foo) result (bar)
implicit none
real :: foo
foo = foo * foo
bar = foo
end function e
! "function name result" vs. "named result" seems to be a stylistic thing,
! except for recursive functions where "named result" is mandatory because
! the function identifier actually refers to the function.
! Moved the return type back inside the function
function f(foo) result (bar)
implicit none
real :: foo, bar
foo = foo * foo
bar = foo
end function f
! Oh look, the :: was optional...
function g(foo) result (bar)
implicit none
real foo, bar
foo = foo * foo
bar = foo
end function g
! Through all of these examples we're getting bitten in the ass without
! knowing it. Function arguments default to intent(inout) - whatever
! variable is supplied as the first argument is getting modified by
! "foo = foo * foo".
! Equivalent to the above, but more explicit. And that once-optional :: is
! now required again.
function h(foo) result (bar)
implicit none
real, intent(inout) :: foo
real bar
foo = foo * foo
bar = foo
end function h
! Let's fix the bug
function i(foo) result (bar)
implicit none
real, intent(in) :: foo
real bar
! Can no longer do this because foo is unmodifiable due to intent(in)
!foo = foo * foo
!bar = foo
bar = foo * foo
end function i
! The minimum definition that has "expected" behaviour? (Notice the :: has
! disappeared again.)
function j(foo)
intent(in) foo
j = foo * foo
end function
! Trick question! It now returns an integer, not a real, because it starts
! with "j". I'm not kidding. Implicit variables are a stupid idea and you
! should always use the compiler flag that turns them off globally
! (-fimplicit-none for gfortran).
! The minimum definition you can expect to actually work correctly.
real function k(foo)
real, intent(in) :: foo
k = foo * foo
end function
end program example
x = 144.00000 y = 144.00000 a(x) = 20736.000
x = 144.00000 y = 144.00000 b(x) = 20736.000
x = 144.00000 y = 144.00000 c(x) = 20736.000
x = 144.00000 y = 144.00000 d(x) = 20736.000
x = 144.00000 y = 144.00000 e(x) = 20736.000
x = 144.00000 y = 144.00000 f(x) = 20736.000
x = 144.00000 y = 144.00000 g(x) = 20736.000
x = 144.00000 y = 144.00000 h(x) = 20736.000
x = 12.000000 y = 144.00000 i(x) = 144.00000
x = 12.000000 y = 144.00000 j(x) = 144
x = 12.000000 y = 144.00000 k(x) = 144.00000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment