"Not defined as function or array" while compiling - fortran

I have inherited some old code where each function is defined as an individual file. I am attempting to write a simple program to test this. I have written test.f a program that at its base calls the function in func.f and then reports the result.
Using ifort -c func.f I created the object file for func.f and then attempted to compile using ifort test.f func.o -o test. This gives me the error that func is not defined as a function or array. Any thoughts?
test.f is
PROGRAM test
REAL :: X,Y
REAL :: FUNC
X = 1.0
Y = func(X)
WRITE(6,*) X
END
and func.f is
FUNCTION func(X)
func = X
RETURN
END

A type declaration statement like
real func
declares that there exists an entity with name func. This may be either:
a function with real result; or
a variable of type real
In isolation, from just this declaration, it is not possible to determine which type of entity func is.
If func is not declared an array and there is no other use of func in the scope which is inconsistent with it being a function, then func is taken to be a function by any reference where it can be a function, such as
real func
print *, func(1)
end
In the absence of an array declaration for func, any use of func in the scope which is inconsistent with func a function will be an error. ifort will generally issue an error message in such case looking like
error #6410: This name has not been declared as an array or a function.
What uses of func in a scope would be inconsistent with func a function? Just about anything that doesn't look like f(...) in an expression. For example:
giving func some attribute a only variable may have
using it as a variable in an assignment statement1
providing explicit initialization
using its name when a reference is required
etc.
real :: func ! Function or variable?
save func ! Function can't be SAVEd
func = 1 ! Function name can't be on the left-hand side
print *, func ! Function name can't be used in an expression
print *, func(1) ! Oops, func isn't a function.
end
(All of these uses are consistent with being an array, we just haven't declared it as such.)
Some type declaration statements make it obvious the entity must be a variable:
real :: not_func = 1.
real, allocatable :: definitely_variable
real :: definitely_array(5)
end
That's all to say: if you intend to use real func to declare an external function func with implicit interface and real result, but you get a warning about "not an array or function" when you try to reference it then you've got something somewhere which means func isn't a function and you haven't said it's an array.
It could be quite boring to check for all cases where func could be misused, so let's make our life easier:
real, external :: func
Although without the external attribute specification the EXTERNAL attribute is applied if func is a function, there's certainly no harm it using it. Indeed, it's good: this way we've told the compiler that func really is a function. Which means that any use of func inconsistent with being a function is an error, instead of the function reference.
Try the previous example with external added.
You can also be precise about func being an external function using an interface block (good practice) or a procedure declaration statement.
1 Although a function reference can be a variable, like in
func(1) = 12 ! func a function not an array
this is only the case when the function result is a pointer. A function with implicit interface cannot have a pointer result so this use is not consistent with func a function. We should also avoid confusion with the statement function
real :: func
func(i) = i+1
This is consistent with func a function, but it's not an external function defined elsewhere.

Related

Overloading functions with optional arguments

I would like to write a procedure which takes an optional argument, which may be of type FooType or of type BarType, such that this program is valid:
module m
implicit none
type :: FooType
end type
type :: BarType
end type
end module
program mwe
use m
implicit none
type(FooType), allocatable :: foo(:)
type(BarType), allocatable :: bar(:)
call func()
call func([FooType()])
call func([BarType()])
call func(foo)
call func(bar)
end program
My current attempt is:
module m
implicit none
type :: FooType
end type
type :: BarType
end type
interface func
module procedure func_FooType
module procedure func_BarType
end interface
contains
subroutine func_FooType(input)
type(FooType), intent(in), optional :: input(:)
write(*,*) 'foo'
end subroutine
subroutine func_BarType(input)
type(BarType), intent(in) :: input(:)
write(*,*) 'bar'
end subroutine
end module
But this does not work. Compiling with either gfortran 10.1.0 or ifort 2021.1 gives the output
foo
foo
bar
foo
bar
The problem is the final call, to func(bar). bar is not allocated, and so if it were passed to an optional argument it would not be present. However, the procedure which gets called is func_BarType, which believes its input is not optional, and so has no way of checking if input is present. Indeed, if I change the input to be a scalar not an array, the call to func(bar) crashes at runtime under gfortran.
I think the only way to do this is with a single function which takes an optional polymorphic argument, so:
subroutine func(input)
class(*), intent(in), optional :: input(:)
if (present(input)) then
select type(input); type is(FooType)
! Code for FooType.
type is(BarType)
! Code for BarType.
class default
! Any other class. Probably throw an error.
end select
else
! Code for input not present.
endif
end subroutine
I'm surprised that there doesn't seem to be a way of doing this without using polymorphic types.

Passing functions, which have derived types as arguments, as arguments in Fortran

I have a subroutine which receives some data and another function as arguments. The function can take as argument this data. The subroutine is just there to call this function with the given data. Now let us assume the data can be of type foo. I would assume that I can also pass data of the from foo derived type bar. Apparently Fortran disagrees.
I have tried to compile the code below with gfortran 9. It fails with the error message:
47 | call funA(x, y, baz)
| 1
Error: Interface mismatch in dummy procedure ‘baz’ at (1): Type mismatch in argument 'y' (CLASS(foo)/CLASS(bar))
Various other attempts of replacing foo by bar yield similar resuts. Using pgfortran 19.4 yields the same error.
module A
implicit none
private
type, abstract, public :: foo
end type foo
public :: funA
contains
subroutine funA(x, y, baz)
integer, intent(in) :: x
class(foo), intent(in) :: y
interface
function baz(x, y) result(z)
import foo
integer, intent(in) :: x
class(foo), intent(in) :: y
integer :: z
end function baz
end interface
write(*,*) baz(x, y)
end subroutine funA
end module
module B
use A
implicit none
private
type, extends(foo), public :: bar
integer :: ii
end type bar
public :: fiz
contains
function baz(x, y) result(z)
integer, intent(in) :: x
class(bar), intent(in) :: y
integer :: z
z = x + y%ii
end function baz
subroutine fiz(x, y)
integer, intent(in) :: x
class(bar), intent(in) :: y
call funA(x, y, baz) ! <---- This causes errors.
end subroutine fiz
end module
program meh
use B
implicit none
integer :: x
type(bar) :: y
x = 1
y%ii = 2
call fiz(x, y)
end program meh
My expectation would have been that since y is of type bar, it is also of type foo and thus I can pass it to funA. The function baz must know that y is of type bar, otherwise it cannot access ii. However the rest of the code doesn't really need to know this, does it?
Where is the error in my reasoning? How can I get the above code to compile and run?
The error pointed to here is in the characteristics of the procedure argument. The procedure dummy argument baz of funA has characteristics which are not matched by the procedure actual argument baz of module B. The dummy argument has second argument (y) of declared type foo whereas the procedure baz passed to it has corresponding argument of declared type bar.
It is not allowed to have this mismatch in characteristics in dummy and actual procedure arguments.
To fix this problem it is necessary to make the dummy arguments y of the dummy baz and module procedure baz to be of the same declared type (probably foo). Of course, you'll then need to work around having y in baz (of module B) having declared type foo: such a y doesn't have a component ii. A quick hack would be to use a select type construct, but there may well be other approaches if a different flow can be designed.
As you can see, often discussions around code like this are helped if various arguments and the like have distinct names.

Fortran Define Parameter from variable

I wish to define a parameter that will not change in my module from a input variable.
Example
module foo
contains
subroutine function1(external_var)
integer, parameter x = external_var(1)
write(*,*) x
end subroutine function1
end module foo
However, this gives an error.
PGF90-S-0087-Non-constant expression where constant expression required

fortran initializing a derived type inline or type casting

I want to know if there is a way to pass a derived type inline in a subroutine. Suppose that I have a module
module test_mod
type a
end type
type b
end type
contains
subroutine test(var)
type(a),intent(in) :: var
...
end subroutine
subroutine test(var)
type(b),intent(in) :: var
...
end subroutine
end module
Where I could implement this module with something like
program testTest
use test_mod
call test(type(a)::temp)
! call test(type(a)::temp) ! or
end program
I know this can be done in c++ using something like (double)(i), but this is a conversion. I'm interested in (I guess) initializing a derived type inline
The syntax you are using is alien to the language, but you can use structure constructors.
It is a function which returns the type and it has the same name as the type. Every derived type has a default one and you can define your own by overriding the type name in a generic interface. The arguments of the default constructor are the type components.
program testTest
use test_mod
call test(a())
end program
You can also use constructors in other situations, in compound expressions, or just on the right hand side of simple assignments
type :: t
real :: x
end type
type(t) :: o
o = t(1.0)
Example of a user-defined constructor:
type :: t
real :: x
end type
interface t
module procedure my_init
end interface
contains
function my_init(...) result(res)
type(t) :: res
...
end function

Fortran errors when using derived types

I am writing some code in Fortran with derived types and encountering problem but still cannot figure out what is going wrong..........................................................................................................................................................................................................................................................................................
make -f vbld.mk
gfortran -c gshapes.f08
gshapes.f08:100.31:
generic, public :: get => get_ellipse, &
1
Error: Undefined specific binding 'get_ellipse_minmax' as target of GENERIC 'get' at (1)
gshapes.f08:136.31:
generic, public :: get => get_cylinder, &
1
Error: Undefined specific binding 'get_cylinder_minmax' as target of GENERIC 'get' at (1)
gshapes.f08:139.15:
procedure :: print => print_cylinder
1
Error: Dummy argument 'cyld' of 'print' at (1) should be named 'elips' as to match the
corresponding argument of the overridden procedure
gshapes.f08:135.15:
procedure :: set => set_cylinder
1
Error: Dummy argument 'cyld' of 'set' at (1) should be named 'elips' as to match the
corresponding argument of the overridden procedure
gshapes.f08:74.31:
generic, public :: get => get_rectangle, &
1
Error: Undefined specific binding 'get_rectangle_minmax' as target of GENERIC 'get' at (1)
gshapes.f08:118.31:
generic, public :: get => get_prism, &
1
Error: Undefined specific binding 'get_prism_minmax' as target of GENERIC 'get' at (1)
gshapes.f08:121.15:
procedure :: print => print_prism
1
Error: Dummy argument 'prsm' of 'print' at (1) should be named 'rect' as to match the
corresponding argument of the overridden procedure
gshapes.f08:117.15:
procedure :: set => set_prism
1
Error: Dummy argument 'prsm' of 'set' at (1) should be named 'rect' as to match the
corresponding argument of the overridden procedure
make: *** [gshapes.mod] Error 1
A generic binding nominates specific bindings that can be considered when the generic binding is referenced in code. Those specific bindings then reference specific procedures (and those specific procedures can be overridden - they might be different specific procedures in extensions).
Your generic bindings are referencing procedure names, not specific binding names. The correct approach is:
TYPE parent
CONTAINS
PROCEDURE :: SpecificBindingA => ProcedureA
PROCEDURE :: SpecificBindingB => ProcedureB
GENERIC :: GenericBinding => SpecificBindingA, SpecificBindingB
END TYPE parent
In code, if there is an object declared TYPE(parent) :: obj, then a reference to obj%GenericBinding will either resolve to obj%SpecificBindingA or obj%SpecificBindingB depending on the type of the actual arguments in the reference. The dynamic type of obj will then determine the actual procedure that is called for a particular specific binding.
The procedures ProcedureA and ProcedureB will need to have their first dummy argument declared appropriate so that it can be a passed object (it will have to be declared CLASS(parent), have the same argument name, etc). Any overrides in extensions of parent will need to vary the type of the passed argument appropriately, and have the characteristics of any other dummy arguments (including the dummy argument name) match.
Alternatively, maybe you just want a generic name for the specific procedures. You do that using an interface block.
INTERFACE GenericName
MODULE PROCEDURE ProcedureA
MODULE PROCEDURE ProcedureB
END INTERFACE GenericName
In this case, a reference GenericName(...) will be resolved to ProcedureA or ProcedureB depending on the arguments in the reference. In this case there is no dynamic lookup of the specific procedure based on the dynamic type of an object.
module shape
implicit none
type, public :: GCoord
real :: x
real :: y
real :: z
end type GCoord
type, extends (GCoord) :: GCentr
end type GCentr
type, extends (GCoord) :: GCornr
end type GCornr
type, public :: Rectangle
type(GCentr) :: cn
type(GCoord) :: pa
real :: b
type(GCornr) :: p1, p2, p3, p4
contains
generic, public :: get => getu, getm
end type Rectangle
contains
subroutine getu (rect, val)
class(Rectangle), intent(in) :: rect
integer, intent(in) :: val
write (*,*) 'GETU'
end subroutine getu
subroutine getm (rect, val)
class(Rectangle), intent(in) :: rect
complex, intent(in) :: val
write (*,*) 'GETM'
end subroutine getm
end module shape