Is it possible to overload a deferred procedure with a non-polymorphic procedure?
I'd like to create an abstract class (Parent) with a procedure (foo) which must be overloaded by every class which extends Parent. I run into problems when I want to extend again, such that a class (Grandchild) extends a class (Child) which extends Parent.
Since Child is not abstract, its foo (foo_Child) must be polymorphic. But then Grandchild inherits foo_Child, rather than being forced to define foo_Grandchild. Further, since I don't want foo_Child to be polymorphic I want to be able to use Child-specific non-polymorphic functions within foo_Child.
module test_module
type, abstract :: Parent
contains
procedure(foo_Parent), deferred :: foo
end type
abstract interface
subroutine foo_Parent(this,input)
import Parent
class(Parent), intent(out) :: this
character(*), intent(in) :: input
end subroutine
end interface
type, extends(Parent) :: Child
contains
procedure :: foo => foo_Child
end type
type, extends(Child) :: Grandchild
! Is not required to define foo=>foo_Grandchild.
! This is not the behaviour I want.
end type
interface Child
module procedure new_Child
end interface
contains
function new_Child(input) result(this)
character(*), intent(in) :: input
type(Child) :: this
end function
subroutine foo_Child(this,input)
type(Child), intent(out) :: this ! Fails: 'this' is not polymorphic.
character(*), intent(in) :: input
this = Child(input) ! Fails if type(Child) is replaced by class(Child).
end subroutine
end module
program test
use test_module
end program
To summarise:
Is there any way of making foo_Child be non-polymorphic but also overload foo_Parent? Or is there a way of calling non-polymorphic functions (at least Child=Child assignment with non-polymorphic rhs) in a polymorphic procedure? If not, is there a workaround?
(I don't want to define class(Child)=type(Child), but will if it's the only option).
The dummy argument that corresponds to the passed object of a procedure binding must always be polymorphic.
The rules of the language for intrinsic assignment do not permit assignment to a non-allocatable polymorphic object. This is because typically such an assignment would be an error akin to slicing - you would undefine the bits of the object that are declared in the dynamic type of the rhs but not in the declared type of the lhs.
A polymorphic object can be downcast to a non-polymorphic object using SELECT TYPE and a type guard that matches the dynamic type of the object. You can also merrily slice to your hearts content via argument association - a polymorphic actual argument can be associated with a non-polymorphic dummy of the same declared type.
Extensions can be forced to implement a binding by making the parent type abstract and making (or leaving) the binding deferred (as you have already done). In your situation that perhaps requires an additional type in your hierarchy.
Parent (abstract) --> Child (abstract) +-> RealChild (concrete)
|-> GrandChild (concrete)
Child in the above might simply leave the foo binding deferred, or it may provide a procedure for that binding and then introduce a new deferred binding that RealChild and GrandChild need to implement.
Related
Consider the following code, which defines an abstract type foo with a deferred procedure sub, and a type foo2 which extends foo:
MODULE m
TYPE, ABSTRACT:: foo
CONTAINS
PROCEDURE(sub_int), DEFERRED:: sub
END TYPE
INTERFACE
SUBROUTINE sub_int(THIS, x)
IMPORT:: foo
CLASS(foo), INTENT(IN):: THIS
DOUBLE PRECISION, INTENT(INOUT):: x
END SUBROUTINE
END INTERFACE
TYPE, EXTENDS(foo):: foo2
CONTAINS
PROCEDURE:: sub
END TYPE
INTERFACE
MODULE SUBROUTINE sub(THIS, x)
CLASS(foo2), INTENT(IN):: THIS
DOUBLE PRECISION, INTENT(INOUT):: x
END SUBROUTINE
END INTERFACE
END MODULE
SUBMODULE (m) s
CONTAINS
MODULE PROCEDURE sub
x= x**2
END PROCEDURE
END SUBMODULE
Is there a way to avoid writing the second interface?
I understand that it is needed in order to declare sub as a module procedure (otherwise the implementation would need to be done in the module, and not in the submodule), but is this the only way to do it?
In other words, is it possible to implement the procedure sub for foo2 without rewriting the entire interface for it?
It is not possible. A separate module subprogram requires an interface block, either in its defining submodule or an ancestor of its defining submodule.
Whether a procedure happens to be nominated by one (or more!) bindings of one (or more!) types is totally irrelevant.
I have intention to point with the same procedure to two different procedures but I have not experienced programmer in Fortran so I need help.
This is my simple code:
module types
type :: type_one
integer, private :: a1,a2
contains
procedure, public :: f_data => set_data_a1
procedure, public :: f_data => cal_data_a2
end type type_one
private :: set_data_a1,cal_data_a2
contains
integer function set_data_a1(this)
class(type_one) :: this
this%a1 = 2
end function set_data_a1
integer function calc_data_a2(this)
class(type_one) :: this
this%a2 = this%a1 + 3
end function calc_data_a2
end module types
program types_pro
implicit none
type(type_one) :: type_obj
type_obj%f_data()
end program types_pro
I got this error:
`There is already a procedure with binding name 'f_data' for the derived type 'type_one' |
Is it possible to call both procedures at the same time with type_obj%f_data()?
A generic name, such as your f_data, allows calling procedures with different input signatures (rank, type, kind, and number of arguments) by the same name. But, because they have the same argument signatures the compiler can't determine which of calc_data_a1 and calc_data_a2 to execute when your code makes a call to f_data.
Which leads me to a question for you: How do you expect the compiler or code to behave ? What do you want the compiler to do ? (OK that was two questions.)
As a general rule, if you want the compiler to execute two procedures you have to make two calls. You could, I suppose, have one procedure call the other if you want both to run when one is called.
If you want to wrap multiple functions behind the same name they have to have different input signatures so that the compiler can work out which one to call.
Obviously my earlier version of this answer wasn't explicit enough:
No, there is no way to write your code to execute two different procedures in response to a single call to one of them. (Unless, that is, the one calls the other.) Furthermore, it is unreasonable to expect a single (procedure) pointer to point, at any one time, at more than one target.
For instance, I have a definition of type A in moduleA:
Module moduleA
implicit none
type A
private
integer::N
contains
...
procedure,pass::f=>f1
endtype
private::f1
contains
real function f1(self,x)
real::x(self%n)
end function
...
end Module
Then I found I meet a trouble when I override function f in other modules since I can not get the value of N. Even though I can have a method to get that, it seems that something like real :: x(self%get()) is impossible in the declaration. I want to keep the rule of "private" in OPP. So what choices can I have?
You cannot do that. At least in the way you describe. It would be better to see an example of the overriding to suggest other options.
The private attribute works differently in Fortran and therefore you should not directly use rules from other languages that use OOP where private means something different.
In Fortran private is about the local module, in C++ it is about the derived classes. This is very different and you cannot use the C++ (or Java, etc.) rules for private in Fortran when private in fact means something else.
To be clear, I assume you wanted this kind of overriding:
real function f2(self,x)
class(B) :: self
real::x(self%get())
end function
You than get these messages:
private.f90(15): error #8497: Illegal use of a procedure name in an expression, possibly a function call missing parenthesis. [GET]
real::x(self%get())
---------------------^
or
real::x(self%get())
1
Error: 'get' at (1) should be a FUNCTION
So the compilers will not accept a type-bound procedure in the declaration. They would accept an ordinary procedure.
This compiles in gfortran, but not in Intel Fortran. But get() must be public, which you might not want:
real function f1(self,x)
class(A) :: self
real::x(get(self))
end function
real function f2(self,x)
class(B) :: self
real::x(get(self))
end function
In ifort I get
error #8383: The dummy arguments of an overriding and overridden binding that correspond by position must have the same characteristics, except for the type of the passed object dummy arguments.
which is weird.
I would like to use the generic name of a function to overload the '*' operator as in the example below:
interface scala
module procedure :: scalapr,scalarp
end interface scala
interface operator(*)
module procedure :: scala
end interface operator(*)
However, compiling with gfortran, I get:
Error: Procedure 'scala' in intrinsic '*' operator at (1) is neither function nor subroutine
Is there any turn-around ?
You must overload with the specific function
interface scala
module procedure :: scalapr,scalarp
end interface scala
interface operator(*)
module procedure :: scalapr, scalarp
end interface operator(*)
The generic is not a module procedure, so it cannot appear in module procedure.
There is also just procedure, but that won't help here. It is for procedures not coming form the current module. But anyway, the functions in the generic interface block must be specific functions.
See Fortran 2008 12.4.3.4 Generic interfaces:
1 A generic interface block specifies a generic interface for each of
the procedures in the interface block. The PROCEDURE statement lists
procedure pointers, external procedures, dummy procedures, or module
procedures that have this generic interface. ...
According to 7.1.6:
5 A function defines the binary operation x1 op x2 if
(2) either
(a) a generic interface (12.4.3.2) provides the function with a generic-spec of OPERATOR (op),
or
(b) there is a generic binding (4.5.5) in the declared type
so the rules above do apply as does the constraint
C1207 (R1206) A procedure-name shall be a nonintrinsic procedure that
has an explicit interface.
A generic-name does not conform to C1207.
When I try to mix both regular procedures and deferred procedures in one abstract type, gfortran balks at any invocation of the regular procedures:
" Error: Base object for type-bound procedure call at (1) is of ABSTRACT type 'tbody' "
type, abstract :: tBody
private
...
contains
procedure :: init => new_Body
...
procedure (contained), deferred :: PointIn
end type tBody
abstract interface
logical(LGT) pure function contained( Body, Point )
import :: tBody, tAffinePoint, LGT
class(tBody), intent(IN) :: Body
type(tAffinePoint), intent(IN) :: Point
end function contained
end interface
subroutine newCuboid( this, ... )
class(tCuboid), intent(OUT) :: this
...
call this%tBody%init( ... )
.... [gfortran halts here]
end subroutine newCuboid
Is there a way to arrange the type tBody so that I can have both abstract, deferred procedures and regular, instantiated procedures?
No.
There's a simple solution - replace call this%tBody%init(...) with call new_Body(...) (you may need to make appropriate accessibility changes).
Possibly feeble rationalisation - you are not resolving the procedure on the basis of the type of the reference (because that's hard coded), so don't use type bound procedure syntax.
Another solution in some cases is to split the type hierarchy further, so that the abstract type tBody has a non-abstract parent that hosts the initial implementation of the "not deferred" procedures.