Some basic questions on Fortran

Can you help please me with some of these problems?

  1. Is there any way to access the ith character in character (let say of length = 9).
    string = ‘spiderman’
    (I assume that fortran uses 1-based indexing.)
    can I access the character at index 1 (which is ‘s’) without using string(1:1)?

  2. Is fortran a “call by reference” (“pass by reference”) language?
    Many people say that python is “call by object deference”, some argues that python is actually “call by value” because every variable stores reference and this reference is copied whenever called.

    I wrote some code to understand. The below written might be irrelevant in concluding that it is call by reference.

     program factorial
     implicit none
        integer, dimension(5) :: a, b, c
        a = (/1, 2, 3, 4, 5/)
        b = (/2, 2, 2, 2, 2/)
        c = (/3, 3, 3, 3, 3/)
        print *, LOC(a), LOC(b), LOC(c)
        a = b
        a(1) = 100
        b(1) = 274
        print *, LOC(a), LOC(b), LOC(c), a, b
     end program factorial
    

    Output:

     6422252     6422232     6422212
     6422252     6422232     6422212         100           2           2           2           2         274           2           2           2           2
    

    So, I can conclude that when a = b was done, a new copy of the array (stored at the memory location of b) was created which was then overwritten at memory location of a. Same phenomenon was observed for basic data types like integer, etc.

  3. Are characters (let’s say of length = 10) mutable in Fortran? Which means that can I directly go and change the character at index 1 without affecting the rest of the indexes?
    In python strings are immutable just like tuples, so I will have to create a totally new character if I want to make any change.

  4. How does fortran store character of length greater than 1. Does it use an array to store?

Regarding (1), string(i:i) is the standard way to refer to the character at index i. I don’t know of an alternative. Regarding (3), yes, characters are mutable, unless declared PARAMETER, so the output of

character (len=3) :: word = "dog"
word(2:2) = "i"
print*,word
end

is “dig”.

Regarding (2), I’d say it’s either pass by reference or value, depending on what arguments are passed. When you want to make a copy of a variable, you can enclose it in parentheses. For example, the program

subroutine twice(i,j)
integer, intent(in)  :: i
integer, intent(out) :: j
j = 2*i
end subroutine twice

program main
implicit none
integer :: i
i = 3
call twice((i),i) ! first argument passed by value, second by reference
print*,i
end program main

gives output 6. Fortran 2003 does have the VALUE attribute.

Note that unless you want to conform the Fortran 90 standard (most compilers support Fortran 2003 if not later), you can write arrays as [4,9] instead of (/4,9/)

1 Like

Very likely as there is no actual call in that code.

There are about 12 pages in the Fortran Standard describing this (Section 15.5.2), the odds that any one of us can summarize it accurately are nil. It’s already as short as it can be!

2 Likes

Thank you @Beliavsky and @themos for your replies. I hope this will help other beginners as well.

@themos is this the Fortran Standard that you were talking about in your reply? If not, can you please send me the link to the Fortran Standard so that I can learn many other things about Fortran. Thanks again!

It is the committee draft of the Fortran 2018 standard. That is the reference document you should use, unless you are ready to pay 198 CHF for the published ISO/CEI 1539-1:2018 standard:

Another excellent reference is “Modern Fortran Explained : Incorporating Fortran 2018”:

Shorter, more readable, less expensive (~47 €) ! But as useful.

The output from your execution is not correct. If you print a and b, you should see all of the elements of the arrays in the output (10 numbers). I tried 3 different compilers (Cray, Intel, gfortran) all look correct:

./a.out
4211776, 4211840, 4211904
4211776, 4211840, 4211904, 100, 4 * 2, 274, 4 * 2

./a.out
7074160 7074192 7074224
7074160 7074192 7074224 100
2 2 2 2 274 2
2 2 2

./a.out
140732880126032 140732880126000 140732880125968
140732880126032 140732880126000 140732880125968 100 2 2 2 2 274 2 2 2 2

It appears there is a bug in the compiler you are using, or you did not past the entire output.

The statement

a = b

causes the value of the array b to be copied into the array a. It is not necessary to allocate any new hidden memory.

The notation string(1:1) is the correct syntax to designate the character in string at location 1.

Depending on the circumstance, Fortran passes procedure arguments by one of three methods: “reference” (the address of the argument is passed), “value” (the value of the argument is passed), or “descriptor” (the address of a descriptor for the argument is passed). Descriptors are sometimes called “dope vectors”.

@Aman,

Welcome to the forum and for your interest in GSoC!

Interesting questions. If you remain interested in Fortran, please try to refer to Modern Fortran Explained as suggested above. You can consider Intel oneAPI toolkit with IFORT Classic compiler for Fortran in conjunction with that book: Intel releases oneAPI Toolkit, free, Fortran 2018 Or, the standard of course!

So as you have noted already, there is an ISO IEC Standard for Fortran similar to C and C++ and that there are quite a few compilers such as Intel IFORT, GCC gfortran, Cray HPE, NAG, IBM, etc. You will notice the standard consciously avoids getting into details on quite a few aspects but instead leaves them as processor (compiler) dependent mechanisms that then allow compilers to adopt suitable implementation designs as long as certain requirements involving actual argument and dummy argument association and storage association, etc. are met. Such aspects pertain to your questions 2 and 4.

Re: your question 2 in terms of calling mechanism, as you look into the possibilities in the standard with various situations of argument association with different arguments (parameters) including explicit-size and assumed-size arrays, assumed-shape arrays, polymorphic objects, arguments of VALUE or VOLATILE attributes, etc., you will notice it’s inappropriate to box Fortran as call by reference even if you find such an (erroneous) allegation in many places.

Re: question 3, note immutability in Fortran can be enforced via the PARAMETER attribute:

character(len=*), parameter :: string = "spiderman" !<-- string is immutable in this instance

Re: question 4 about CHARACTER object storage, refer to section 19.5.3.2 Storage sequence in the 18-007r1 document you linked above for some details.

Re: “can I access the character at index 1 (which is ‘s’) without using string(1:1)?” technically yes - see a convoluted approach below. The indexer facility (string(i:i)) is the most convenient way, I feel, to work with a substring in a given CHARACTER variable.

   character(len=:), allocatable, target :: string
   character(len=1), pointer :: s
   string = "spiderman"
   s => string
   print *, "string = ", string
   print *, "s = ", s
   s = "S"
   print *, "string = ", string
end 

C:\Temp>ifort s.f90
Intel® Fortran Intel® 64 Compiler Classic for applications running on Intel® 64, Version 2021.1.2 Build 20201208_000000
Copyright © 1985-2020 Intel Corporation. All rights reserved.

Microsoft ® Incremental Linker Version 14.28.29337.0
Copyright © Microsoft Corporation. All rights reserved.

-out:s.exe
-subsystem:console
s.obj

C:\Temp>s.exe
string = spiderman
s = s
string = Spiderman

C:\Temp>

1 Like