Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using methods from an abstract parent type

168 views
Skip to first unread message

Arjen Markus

unread,
Feb 1, 2021, 11:16:29 AM2/1/21
to
A colleague of mine ran into a problem with attempting to use a method from an abstract parent class. The problem is illustrated with this code:

! parent_methods.f90 --
! How to use the methods from an abstract parent?
!
! If the parent class is not abstract, it all works
!
module abstract_parent
implicit none

type, abstract :: parent
!type :: parent
integer :: x
integer, allocatable, dimension(:) :: y
contains
procedure :: alloc
end type parent

abstract interface
subroutine base_fnc( this )
import parent
class(parent), intent(in) :: this
end subroutine base_fnc
end interface

contains
subroutine alloc( this, size )
class(parent), intent(inout), target :: this
integer, intent(in) :: size

allocate( this%y(size) )
end subroutine alloc

end module abstract_parent

module use_parent
use abstract_parent

implicit none

type, extends(parent) :: child
integer, allocatable, dimension(:) :: z
contains
procedure :: alloc => alloc_child
end type child

contains
subroutine alloc_child( this, size )
class(child), intent(inout), target :: this
integer, intent(in) :: size

!
! This fragment does not work:
!

class(parent), pointer :: p

p => this%parent
select type (p)
class is (parent)
call p%alloc(size)
end select

allocate( this%z(size) )

!
! But neither does:
!
call this%parent%alloc(size)
end subroutine alloc_child

end module use_parent

Both Intel Fortran and gfortran complain about the pointer assignment p => and the use of parent%alloc. The error messages are similar, so I am probably do something wrong that should be obvious, but I cannot see what.

Here are the messages from gfortran (10.2.0):

$ gfortran -c parent_methods.f90
parent_methods.f90:56:20:

56 | p => this%parent
| 1
Error: Nonpolymorphic reference to abstract type at (1)
parent_methods.f90:67:13:

67 | call this%parent%alloc(size)
| 1
Error: Base object for type-bound procedure call at (1) is of ABSTRACT type ‘parent’

And these are the messages from Intel Fortran (2018):

Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 18.0.5.274 Build 20180823
Copyright (C) 1985-2018 Intel Corporation. All rights reserved.

parent_methods.f90(56): error #8314: If the rightmost part-name is of abstract type, data-ref shall be polymorphic. [PARENT]
p => this%parent
--------------^
parent_methods.f90(67): error #8314: If the rightmost part-name is of abstract type, data-ref shall be polymorphic. [PARENT]
call this%parent%alloc(size)
--------------^
parent_methods.f90(67): error #8422: If the component immediately preceding the type-bound procedure is abstract, the entire data reference before the procedure name must be polymorphic. [PARENT]
call this%parent%alloc(size)
--------------^
compilation aborted for parent_methods.f90 (code 1)

Both complain about the non-polymorphc character of the accessing of the parent, but I see no way to solve these complaints.

If I leave out the keyword abstract for type(parent), then both happily compile the code.

Regards,

Arjen

FortranFan

unread,
Feb 1, 2021, 12:57:31 PM2/1/21
to
On Monday, February 1, 2021 at 11:16:29 AM UTC-5, arjen.m...@gmail.com wrote:

> A colleague of mine ran into a problem with attempting to use a method from an abstract parent class. The problem is illustrated with this code:
> ..
> Both complain about the non-polymorphc character of the accessing of the parent, but I see no way to solve these complaints.
>
> If I leave out the keyword abstract for type(parent), then both happily compile the code.
> ..

See this recent thread at the Fortran Discourse site re: the reference to the abstract parent in extended types and some options if an overriding of the binding-name is of interest:
https://fortran-lang.discourse.group/t/call-overridden-procedure-of-abstract-parent-type/590/15?u=fortranfan

Arjen Markus

unread,
Feb 1, 2021, 1:54:30 PM2/1/21
to
On Monday, February 1, 2021 at 6:57:31 PM UTC+1, FortranFan wrote:
Ah, thanks - I had seen the title, but had not read it yet. I will try this workaround!

Regards,

Arjen

gah4

unread,
Feb 1, 2021, 4:37:12 PM2/1/21
to
On Monday, February 1, 2021 at 8:16:29 AM UTC-8, arjen.m...@gmail.com wrote:
> A colleague of mine ran into a problem with attempting to use a method from an abstract parent class. The problem is illustrated with this code:



(snip)

> type, extends(parent) :: child
> integer, allocatable, dimension(:) :: z
> contains
> procedure :: alloc => alloc_child
> end type child

I sort-of understand Java abstract classes, so maybe that helps.

In Java, you can not instantiate an abstract class. There are no objects
of that class, only a child of the class.

> contains
> subroutine alloc_child( this, size )
> class(child), intent(inout), target :: this
> integer, intent(in) :: size
>
> !
> ! This fragment does not work:
> !

I think in the Java sense, that you can't have a variable of the
class of an abstract class.

All subclasses would override all methods, or reference the methods
of the abstract class.


> class(parent), pointer :: p

Given that, what happens if you change the above to child instead of parent?

> p => this%parent
> select type (p)
> class is (parent)
> call p%alloc(size)
> end select

And I suspect that since there are no objects of the parent class,
that you can't test for them.

> allocate( this%z(size) )
>
> !
> ! But neither does:
> !
> call this%parent%alloc(size)
> end subroutine alloc_child
>
> end module use_parent
>
> Both Intel Fortran and gfortran complain about the pointer assignment p => and the use of parent%alloc. The error messages are similar, so I am probably do something wrong that should be obvious, but I cannot see what.

Abstract methods are methods that must be overridden by all subclasses.
A class with any abstract method must be abstract, though it can also have
non-abstract methods.

A favorite, if not quite realistic, example is an animal class with the sound method.
There are then subclasses dog, cat, cow, which each implement sound.

In Java, and I presume Fortran, there are methods that are not overridden in the subclass
that are still available to objects of the subclass.

gah4

unread,
Feb 1, 2021, 5:51:15 PM2/1/21
to

OK, I tried to write a similar class in Java, and got the error:

parent.java:44: parent.child is not abstract and does not override abstract method base_fnc() in parent

I presume base_fnc is supposed to be abstract, as that is what it says.

In any case, I then added a base_fnc method to child, and it compiles.
Here is what it looks like, between comments of the Fortran routine:

//module abstract_parent
//implicit none

public abstract class parent {
int x;
int[] y;

//type, abstract :: parent
//!type :: parent
//integer :: x
//integer, allocatable, dimension(:) :: y
//contains
//procedure :: alloc
//end type parent

abstract void base_fnc();

//abstract interface
//subroutine base_fnc( this )
//import parent
//class(parent), intent(in) :: this
//end subroutine base_fnc
//end interface

void alloc(int size) {
y=new int[size];
}
//contains
//subroutine alloc( this, size )
//class(parent), intent(inout), target :: this
//integer, intent(in) :: size
//
//allocate( this%y(size) )
//end subroutine alloc
//
//end module abstract_parent
//
//module use_parent
//use abstract_parent
//
//implicit none
//

public class child extends parent {
int[] z;
void alloc(int size) {

//type, extends(parent) :: child
//integer, allocatable, dimension(:) :: z
//contains
//procedure :: alloc => alloc_child
//end type child
//
//contains
//subroutine alloc_child( this, size )
//class(child), intent(inout), target :: this
//integer, intent(in) :: size
//
//!
//! This fragment does not work:
//!
//
//class(parent), pointer :: p
//
//p => this%parent
//select type (p)
//class is (parent)
super.alloc(size);
//call p%alloc(size)
//end select

z=new int[size];
}
void base_fnc() {
}
}

//allocate( this%z(size) )
//
//!
//! But neither does:
//!
//call this%parent%alloc(size)
//end subroutine alloc_child
//
//end module use_parent
}

I wrote child as an inner (nested) class, otherwise it needs to be in its own file.
I don't know if that is what you wanted, or if Fortran has nested class.

gah4

unread,
Feb 1, 2021, 6:29:16 PM2/1/21
to
OK, without inner class, without all the comment, and with a main to
test it out:
(It is indented, but I think that is lost when I post it.)

public abstract class parent {
int x;
int[] y;
abstract void base_fnc();
void alloc(int size) {
y=new int[size];
}
}

public class child extends parent {
int[] z;
void alloc(int size) {
super.alloc(size);
z=new int[size];
}
void base_fnc() {
}
}

public class that {
public static void main(String args[]) {
child a = new child();
a.alloc(30);
a.x=10;
a.y[3]=20;
a.z[3]=30;
System.out.format("%d %d %d%n", a.x, a.y[3], a.z[3]);
}
}

Note that all the references are now to child, and not to parent,
but it knows about x and y from parent.

child calls the alloc method in parent as super.alloc(size).

Ev. Drikos

unread,
Feb 2, 2021, 5:37:53 AM2/2/21
to
On 01/02/2021 18:16, Arjen Markus wrote:
> ... The problem is illustrated with this code:
>

This issue sounds familiar to me and I see I've a relevant example:
https://gist.github.com/drikosev/6fa28d8c9ba771d4e59b97f8f3bb4f89

Where, I see that I can access various members of the base class (ie c)
and just confirmed that I can call the "init" method of the base class
from the init method of a subclass also if I uncomment this:

!call this%based_t%init()

Admittedly, my Fortran skills are obviously limited and you may have
other objections for this example but the workaround would likely work
in your case also, or I've not understood the question.


Regards,
Ev. Drikos
0 new messages