Reputation: 2489
I am still wrapping my head around Fortran with an "object oriented" flavor.
Is it possible to initialize a variable in a derived type, and what if I'd like that variable to be a parameter
?
For example, a classic animal
, cat
, bee
set of types that should set the number of legs of each animal:
animal module
module animal_module
implicit none
type, abstract :: animal
private
integer, public :: nlegs = -1
contains
...
cat module
module cat_module
use animal_module, only : animal
implicit none
type, extends(animal) :: cat
private
! error here about redefining nlegs...
integer, public :: nlegs = 4
...
I've found online the keyword initial
, but my compiler (Intel) complains about the keyword with a syntax error.
I've tried a custom constructor but apparently I am unable to write one for derived types. This is my attempt, only on the cat type:
module cat_module
use animal_module, only : animal
implicit none
type, extends(animal) :: cat
private
real :: hidden = 23.
contains
procedure :: setlegs => setlegs
procedure :: speak
end type cat
interface cat
module procedure init_cat
end interface cat
contains
type(cat) function init_cat(this)
class(cat), intent(inout) :: this
this%nlegs = -4
end function init_cat
...
program oo
use animal_module
use cat_module
use bee_module
implicit none
character(len = 3) :: what = "cat"
class(animal), allocatable :: q
select case(what)
case("cat")
print *, "you will see a cat"
allocate(cat :: q)
...
print *, "this animal has ", q%legs(), " legs."
As the animal
type has integer, public :: nlegs = -1
, I expected the cat
to have -4
legs, but alas, it's still -1
.
Upvotes: 1
Views: 425
Reputation: 32366
It is not possible for a component to be a named constant. Also, it isn't possible to declare a component of an abstract type and then define default initialization for its value in an extending type. Attempting to redeclare the component with default initialization leads to the error of the question.
High Performance Mark's comment offers one route: provide a custom constructor for each extending type setting the value appropriately. You can further set the component to private for encapsulation or protection.
Alternatively, you can provide a "getter" type-bound procedure which references a named constant:
module animal_module
implicit none
type, abstract :: animal
contains
procedure(getter), deferred :: nlegs
end type animal
abstract interface
integer function getter(creature)
import animal
class(animal) creature
end function getter
end interface
end module animal_module
module cat_module
use animal_module, only : animal
implicit none
type, extends(animal) :: cat
contains
procedure :: nlegs => nlegs_cat
end type cat
contains
integer function nlegs_cat(creature)
class(cat) creature
integer, parameter :: my_cat_has_legs=3
nlegs_cat = my_cat_has_legs
end function nlegs_cat
end module cat_module
use cat_module
implicit none
class(animal), allocatable :: fido
fido = cat()
print*, "Fido has", fido%nlegs(), "legs"
end
Finally, initial
is not standard Fortran (and would have similar problems).
Upvotes: 2