4
votes

I am copying a variable of certain class in another of the same class. The compiler happily compiles this but I am worried that at run time the dynamic types may differ. Do I need to test that the two objects are of the same dynamic type to prevent copying rectangle in a square say or may I trust the compiler? What happens if a rectangle is copied in a square accidentally?

What I am trying to do is the following:

type :: simVars
        class(stateVars), dimension(:), allocatable :: svars
        integer                                     :: count_
    contains
        procedure :: init    => init_simVars
        procedure :: destroy => dest_simVars
        procedure :: add     => add_to_simVars              ! adds an observation to the time series
end type simVars

subroutine init_simVars(this,n)
!--> VERSION 1
    class(simVars), intent(inout) :: this
    integer,        intent(in)    :: n

    allocate( this%svars(n) )

    this%count_ = 0
end subroutine init_simVars

subroutine init_simVars(this,n,sVarsIni)
!--> VERSION 2
    class(simVars), intent(inout) :: this
    integer,        intent(in)    :: n
    class(stateVars), intent(in)  :: sVarsIni

    allocate( this%svars(n),source=sVarsIni )

    this%count_ = 0
end subroutine init_simVars

subroutine add_to_simvars(this,svars)
    class(simVars),   intent(inout) :: this
    class(stateVars), intent(in)    :: svars

    this%count_ = this%count_+1

    this%svars(this%count_) = svars
end subroutine add_to_simvars

subroutine doSimulation(simHist,sVarsIni)
    class(simVars),   intent(out) :: simHist
    class(stateVars), intent(in)  :: sVarsIni
         !--> dynamic type 'stateVars1'

    class(stateVars), allocatable :: sVars   ! will be source allocated from 'iniState'

    ! initialize the state of the economy
    allocate( sVars, source=sVarsIni )    ! "copies" 'sVarsIni' in 'sVars'

    ! initialize 'simHist'
    !--> VERSION 1:
    call simHist%init(nYears)
    !--> VERSION 2:
    call simHist%init(nYears,iniState)

    ! save today's variables
    call simHist%add(sVars)
    ...
end subroutine doSimulation

Compiler (ifort 14) happily compiles both versions but I strongly suspect that VERSION 1 is wrong. In init_simVars this%svars will be allocated to dynamic type stateVars, in add_to_simvars sVars will have dynamic type stateVars1 and a copy in this%sVars (of type stateVars) will be attempted. I am quite surprised that the compiler compiles this even though it cannot determine the dynamic type of sVars in add_to_simvars. What would happen at run time, a seg fault or what?

VERSION 2 I believe is correct however I am somewhat reluctant to trust the compiler here therefore I am thinking I should ASSERT that this%sVars and sVars have the same dynamic type (ASSERT(SAME_TYPE_AS(this%sVars, sVars) ))? Is this a real concern or am I worried too much?

Another question is what happens when I do allocate( this%svars(n),source=sVarsIni ). I want to allocate the array this%sVars to be of size n and dynamic type sVarsIni. However sVarsIni is a scalar. Will it do what I want?

1

1 Answers

2
votes

The difference is in these lines

allocate( this%svars(n) )

vs.

allocate( this%svars(n),source=sVarsIni )

where this%svars is class(svars) allocatable array and svarsIni is an class(stateVars) dummy argument.

That indeed changes a lot.

In the first case, it allocates it to the declared type, which is svars, in the other case it allocates to the dynamic type of the dummy argument, which is at least stateVars.

If you do version 1, it should than fail at add_to_simvars, because the dynamic types won't match.

I don't know if you overloaded the assignment in there or not. If you didn't it shouldn't even compile, because of the intrinsic assignment of polymorphic objects.