Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28445 Discussions

Creating base data for use in extended types

NotThatItMatters
Beginner
409 Views

I have a number of types declared which extend a base type with their own functionality.  I came to notice that many of them had similar data structure so I decided to incorporate this data structure into the base class.  The declarations might be the following:

TYPE Base
    REAL, PRIVATE :: Apple = 0.0
    REAL, PRIVATE :: Banana = 1.0
CONTAINS
    PROCEDURE :: Get_Apple
    PROCEDURE :: Get_Banana
    PROCEDURE :: Set_Apple
    PROCEDURE :: Set_Banana
END TYPE Base

REAL FUNCTION Get_Apple(this)
    CLASS (Base), INTENT(IN) :: this

    Get_Apple = this%Apple
END FUNCTION Get_Apple
! Similar FUNCTION for Get_Banana
SUBROUTINE Set_Apple(this, vAppleValue)
    CLASS (Base), INTENT(INOUT) :: this
    REAL, INTENT(IN) :: vAppleValue

    this%Apple = vAppleValue
END SUBROUTINE Set_Apple
! Similar SUBROUTINE for Set_Banana

Now in the extended types, access to Apple and Banana are available with the procedures.  The question is, outside of the extended types, how might I "Get_Apple" or "Get_Banana".  That is, if I have an instance of

TYPE, EXTENDS(Base) :: Fruit
    REAL, PRIVATE :: Mango
    REAL, PRIVATE :: Kiwi
CONTAINS
    PROCEDURE :: Get_Huh
END TYPE Fruit

how might I get Apple or Banana?  Simple calls to Get_Apple or Get_Banana do not suffice despite the fact I can use them "internally" within procedures in Fruit.

0 Kudos
5 Replies
Steve_Lionel
Honored Contributor III
409 Views

Assuming you have:

Type(Fruit) :: Durian

you can do:

something = Durian%GetApple()

When you extend a type, the type inherits all of the accessible components and type-bound procedures of the parent. In the example you posted, while the components Apple and Banana are private, the TBPs are not. This is in fact the desirable way of organizing things.

Or am I not understanding your question?

0 Kudos
NotThatItMatters
Beginner
409 Views

Thank you, Dr. Fortran Emeritus.  That was precisely what I was doing, but failing.  Per usual, there was something behind the scenes causing grief.  Let me explain.  The declaration of TYPE Fruit was encased in a module as follows:

MODULE Fruit_Module
USE Base_Module, ONLY : Base
TYPE, EXTENDS(Base) :: Fruit
! Blah, blah, blah
END MODULE Fruit_Module

But the declaration of Fruit in the external routine was something along the lines of

SUBROUTINE Cultivate(Orchard)
    USE Fruit_Module, ONLY : Fruit
    TYPE (Fruit), POINTER :: Orchard

    REAL Pome

    ! This will not compile because Fruit has no access to Get_Apple!
    Pome = Orchard%Get_Apple()
END SUBROUTINE Cultivate

What needs to happen is

SUBROUTINE Cultivate(Orchard)
    USE Base_Module, ONLY : Base
    USE Fruit_Module, ONLY : Fruit
    TYPE (Fruit), POINTER :: Orchard

    REAL Pome

    ! This will compile because Fruit%Base has access to Get_Apple!
    Pome = Orchard%Get_Apple()
END SUBROUTINE Cultivate

Once again, thank you for the reassurance that my construction was correct.  It was the underpinnings which were lacking.

0 Kudos
NotThatItMatters
Beginner
409 Views

Now I am having some more trouble with my Base class and its use with Fruit of many types.  I wrote an external routine which applied to Fruit only.  I then needed to use that routine for Durian without changing anything within the routine.  In essence the routine is a carbon copy, only with Durian replacing Fruit.

The idea I thought would be to put the routine within Base with the argument in question now declared as CLASS (Base).  Then the routine would be accessed from the Fruit class or the Durian class being as CLASS (Base) is polymorphic.

Unfortunately, there is an internal CALL within the routine to another CLASS which is now not compiling.  The complaint is the "this" argument type differs from the type of the dummy argument.  The "this" argument is declared as

CLASS (Base), INTENT(INOUT) :: this

Within the called routine in the other CLASS it is declared as

CLASS (Base), TARGET, INTENT(INOUT) :: Tomato

No matter how I swing it, I cannot get the two arguments to sync.  I am always getting error #6633.

0 Kudos
Steve_Lionel
Honored Contributor III
409 Views

It would help us help you if you posted a small but complete example of what you are trying.

0 Kudos
NotThatItMatters
Beginner
409 Views

I have a fix for the problem I quoted.  The fix is to make the routine an external routine.

SUBROUTINE HandleFruit(FB, A, B)

    USE Base_Module, ONLY : Base
    CLASS (Base), INTENT(INOUT) :: FB
    REAL, INTENT(INOUT) :: A
    REAL, INTENT(INOUT) :: B

    TYPE (OtherClass) :: OC

    CALL OC%SolutionMethod(A, B, FB)
END SUBROUTINE HandleFruit

With the Base class polymorphic, I can call this routine for any FB argument which extends Base.  This is precisely what I need to do.  I am unsure why I would have wanted routine HandleFruit in the Base class.  It should be an external routine.

0 Kudos
Reply