Created
July 18, 2012 11:33
-
-
Save alanbriolat/3135713 to your computer and use it in GitHub Desktop.
The many faces of function definition in Fortran 95
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fortran_hell.f95:146.12: | |
j = foo * foo | |
1 | |
Warning: Possible change of value in conversion from REAL(4) to INTEGER(4) at (1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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