Override default component initialization

Override default component initialization

Hi,

I understand the following is not legal:

module foo
type :: bar
    integer :: a=53
end type

type, extends(bar) :: rab
    integer :: a=-33333 !!! Redefine default initialization
end type
end module

I think this would be quite practical. The only workaround is implementing clumsy constructor wrappers...

Any thoughts?

10 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

I prefer not to use default initialization; I use constructors instead.  And the Fortran 2003 feature of being able to name an interface block the same as the type name gives me options to apply generics on constructors that are sufficient and flexible enough for my needs.

I also tend to use constructors, but in this very particular case, the default constructors suit me perfectly. There are no additional components that I need to initialize by hand, etc. But sure, the initializer (using the interface to use the same name as the type as you said) is the one I had to implement so far...

What you propose looks like a duplicate component name declaration. I understand what you want to accomplish, but that's just not how the language tends to work. As you found, it is easy to write your own constructors.

Retired 12/31/2016

Hi Steve,

But why would it be a problem? As long as the type of the component is identical to the parent one, redefining the default initialization should not break anything.

Along these lines, I have another question. What is the correct way to set inherited private components? Let's suppose I have the following types:

module foo
    type, abstract :: Dad
        private
        integer :: i
    end type

    type, extends(Dad) :: Son
    end type
end module

program main
    use foo

    type(Son) :: guy

    guy=Son(i=3)      ! i is private
    guy%dad=Dad(i=3)  ! Dad cannot be "instantiated", it's abstract
end program

...

What is the correct way to set the component i of something variable? Are getters/accessors the only possibilities?

 

Extended derived types (i.e., children class) have access to parent members, so you can add a "setter" method to your child class: say you create SUBROUTINE called SetI which takes an argument ValueOfI.  Your program can then invoke this as CALL Son%SetI(ValueOfI=3).

Well, this is not 100% true. Dad's private component is accessible if Son is defined in the same module. The following code does not compile:

module foo
    implicit none
    public :: Dad

    private
    type, abstract :: Dad
        private
        integer :: i
    end type
end module

module foo2
    use foo
    implicit none

    public :: Son

    private
    type, extends(Dad) :: Son
    contains
        procedure :: set_i
    end type

    interface Son
        module procedure :: Son_init
    end interface
contains
    subroutine set_i(self,i)
        class(Son), intent(inout) :: self
        integer                   :: i
        self%i=i
    end subroutine

    function Son_init(i) result(new)
        integer, intent(in) :: i
        type(Son)           :: new

        new%i=i
    end function
end module

program main
    use foo2
    implicit none

    type(Son) :: guy

    guy=Son(i=3)
end program

 

Yep, that's one of the limitations of the current Fortran standard, including 2008.  So you have to either apply PUBLIC attribute to component i in the ABSTRACT type or include both the parent and child in the same module.

I end up picking one of these options depending on my needs.  I usually create a concrete base type off the abstract in the parent module with "getter" and "setter" methods; child modules then extend the concrete type instead of the abstract.

In one case, I ended up with several concrete types (analogy: abstract shape class; concrete bases for 2-D and 3-D; children: triangle, circle, etc. for 2-D and sphere, cylinder, pyramid, etc. for 3-D), abstract and concretes all in one (parent) module, but the children were in their own individual modules.

And yes, this won't satisfy OOP-purists but one is constrained by the language features.

I think the constructor method is definitely the way to go here; a little bit more typing, but the client code can remain unchanged, so you don't have to repeat yourself:

module foo
  implicit none
  private
  public :: bar ,rab
  type :: bar
     private
     integer :: a=53
  end type
  type, extends(bar) :: rab
  end type
  interface rab
     procedure :: constructor
  end interface
contains
  function constructor(a) result(res)
    integer ,optional ,intent(in) :: a
    type(rab)                     :: res
    res%a = -33333
    if ( present(a) ) res%a = a
  end function
end module

If you want to allow the child and the parent to be contained in separate modules, you could create a type bound setter method for the abstract type (you could even make the input argument optional, and use a default if the input argument is omitted) then call the setter method from the constructor. One downside here, however, is that the setter method will now be publically exposed.

module foo
  implicit none
  private
  public :: bar
  type :: bar
     private
     integer :: a=53
   contains
     procedure :: a_setter
  end type
contains
  subroutine a_setter(this,a)
    class(bar)        ,intent(out) :: this
    integer ,optional ,intent(in)  :: a
    res%a = 53
    if ( present(a) ) this%a = a
  end subroutine
end module
module oof
  use foo
  implicit none
  private
  public :: rab
  type, extends(bar) :: rab
  end type
  interface rab
     procedure :: constructor
  end interface
contains
  function constructor(a) result(res)
    integer ,optional ,intent(in) :: a
    type(rab)                     :: res
    call res%a_setter(-33333)
    if ( present(a) ) call res%a_setter(a)
  end function
end module

 

-Zaak

Yep, Zaak, this is pretty much exactly the only solution I had figured so far.

Thanks!

Leave a Comment

Please sign in to add a comment. Not a member? Join today