Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

large number of optional arguments

hannahse
Beginner
1,706 Views

I would like to make a function or subroutine that handles arguments as flexibly as the MAX function. That is, pass in 1 to n individual integer variables . But I have no idea how to declare the variables. All the examples of optional variables I see have optional variables with individual names. Ideally, I would like them assigned to a single dimension array within the function (or subroutine) but passed in as individual values. Its too cumbersome to name (for example) 20 individual variables and check them all with separate if present statements. I need a do loop construct to check if they are present and if so do an operation with them. Is this possible with FORTRAN?

0 Kudos
10 Replies
IanH
Honored Contributor III
1,706 Views

No. If the variables are all scalars, all integer (or all of the same type) and their position in the argument list doesn't matter, why don't you directly pass in an array instead? [fortran]! In a module somewhere...

FUNCTION my_function(arr) INTEGER, INTENT(IN) :: arr(:) INTEGER :: my_function

!****

! Some fancy operation on an array here...

END FUNCTION

my_function r = my_function([1, 2, 3, some_integer_scalar_variable, ix * iy])[/fortran]

0 Kudos
hannahse
Beginner
1,706 Views
Thanks for the suggestion but I don't want the calling routine to have to store the data into an array. I have a rather long well established program and I want to add a function (or subroutine) that can be used over and over again on various collections of same type existing variables. The variables are individually named for their purpose and don't belong in an array. I really have 2 goals here. One is to find out if a user defined function can be as flexible as some of the intrinsic functions that seem to be able to take in arrays and/or comma separated variables like the max and min functions. The other goal is my specific application. I am trying to replace several ugly write/format paired statements with a generic routine that does the same thing but the routine would have one write statement and one format. I would pass in 1 to n pairs of labels and values. The routine would then write a modified version of the label (tags if you like), the value, and a differently modified version of the label one pair per line. I could solve this several ways. I could leave the existing code alone. I could write a generic subroutine to handle one pair (I already have this) and then call it multiple times but that means adding 1 to n call statements and I don't want that. I could create arrays to hold the labels and values but that would mean adding all of the assignment statements everywhere I want to do this. But my preferred solution would be to have 1 to n optional pairs ( I could live with n of about 20) of a string variable followed by an integer in the argument list. Then the subroutine would process them in pair sequence until it found a not present. I have just thought of another alternative. I could create a function, f, that would take in one pair and return a string representing one line of output. Then replace the existing complex write/format pairs with write(unit, '(a/)' )f(label1, var1), f(label2, var2), ... That wouldn't be too bad as long as I keep the name of the function short but could get cumbersome with a longer name. But whatever the workaround, I would still like to know if FORTRAN has the capability to make a function as flexible as the intrinsic max. My guess is no. FORTRAN has come a long way since the days of arithmetic if's but I'm thinking it hasn't got that far yet.
0 Kudos
Steven_L_Intel1
Employee
1,706 Views
Right - there are things intrinsics can do that you can't do in Fortran code. An arbitrary number of optional arguments is one of these.
0 Kudos
hannahse
Beginner
1,706 Views
I ended up implementing a generic function for a single pair of inputs. It returns a string representing an entire line of output. Then used the function within a write statement for each pair of inputs. I used continuation lines to put each function call on a separate line of the source code. It looks clean and easy to maintain or extend. Much better than the complex format statements that had been constructed. I suspected FORTRAN was not quite up to the other approach but but thought it was worth asking. Thanks for the response.
0 Kudos
JVanB
Valued Contributor II
1,706 Views

I don't think the solution with 2*20 optional arguments need be all that bad, see opt1.f90. You could define a UDT with default initialization and invoke with an extra layer like [fortran]call opt2(t20(label1,var1,label2,var2,label3,var3))[/fortran] see opt2.f90. Or you could use an assumed-shape array of structures like call [fortran]opt3([a1(label1,var1),a1(label2,var2),a1(label3,var3)])[/fortran] see opt3.f90.

0 Kudos
hannahse
Beginner
1,706 Views
Thank you. I like all 3 of those. They demonstrate features I'm not well grounded in. Need to study and come back with 2 or 3 questions. But the first that jumps out is the * as the 3rd parameter in sub of opt1 and the associated *10 in the call. I've never seen that. What does it do? Won't the calls to sub generate a run time error if the parameters are not present.
0 Kudos
IanH
Honored Contributor III
1,706 Views
The * in the dummy argument list for a subroutine indicates an alternate return. At the subroutine call you provide a statement label in the scope of the caller, prefixed with a * (hence the "*10"), that the subroutine can elect to continue execution at when the subroutine returns. Note the 1 after the RETURN keyword in the return statement in the subroutine - that indicates "return from this subroutine and resume execution at the label associated with the first * in the dummy argument list (if there is at least one * in that dummy argument list)". In some respects they are a very crude form of exception handling. They are an obsolescent feature of the language in recent standards. I'd be a little twitchy about using them in new code. I'd vote for opt3.
0 Kudos
JVanB
Valued Contributor II
1,706 Views
When the calling procedure has an optional dummy argument it can pass it along to another procedure without fear of it causing an exception due to its not present status when the corresponding dummy argument in the other procedure is also optional. Of course in the next procedure in the call chain the optional dummy argument will have the same same present/not present status as it did in the calling procedure. In the opt1.f90 example this feature was used to defer the testing of the optional dummy arguments to an internal subroutine because due to the limitations of the language a loop of length 20 had to be written out inline. Well, it didn't actually have to be because you can treat the stack like an array in Fortran just like in C but this gets complicated especially for 64-bit calling conventions where the first few (or several in Linux) arguments aren't passed on the stack and the compiler may get a little bitchy when it sees calls to the same procedure with an implicit interface but different number of arguments and you would have to set the compiler to pass mixed string lengths, but this is getting compilcated, right? Ian seems to have provided an excellent discussion about alternate returns. This particular case seems to be a good match for the feature, even if it's marked as obsolescent because it permits us to write out each effective loop iteration as but a single line of code. If it bugs you, you could change subroutine sub to function fun which does what sub did for present arguments and returns .FALSE. and returns .TRUE. for any not present argument. The each line of the expanded loop could be written as: if(fun(s1,n1)) return
0 Kudos
Marcio_Pmz
Beginner
1,706 Views
I would try to create a pointer to the subroutine and then make a present search. But, I really don't know if it ispossible to use pointers in this sense in Fortran. Just a guess!
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,706 Views
Steve, and Repeat Offender RE: opt3([a1(label1,var1),a1(label2,var2),a1(label3,var3)])see opt3.f90 In particular Steve Has it been brought up with the FORTRAN standards committee to have a construct like [an, array, constructed, here] Whereby you have: [reference(an), reference(array), reference(constructed), reference(here)] or references([an, array, constructed, here]) IOW the construct produces an array of references or pointers. This may require the types of each element to be the same. A call to an external subroutine effectively does this on the calling side, but the FORTRAN receiving side does not have an indefinate variable number of args. You might be able to call a C routine
0 Kudos
Reply