constructorfortranabstract-classfortran2008

Fortran constructor of abstract class initializing private variables


I'm beginning with Fortran and I wanted to try a pretty simple example - one abstract class Connection, then its derived class IntervalConnection, while Connection class would have a constructor defined and IntervalConnection would inherit this constructor.

In this constructor I have several private variables, which I need to initialize.

The problem is, I'm getting following error, when trying to create a new object: Connection.f08:152:10:

    con = IntervalConnection(n1_p, n2_p, 5.0)
          1
Error: Component ‘input_neuron’ at (1) is a PRIVATE component of ‘connection’

I suppose I'm not defining the constructor new_connection correctly. Could you, please, tell me, how should I implement it in a better way?


My code

module Connection_mod
    implicit none

    public

    ! TODO smazat
    type :: Neuron
        real, private :: state

        contains
            procedure :: get_state => get_state_impl
            procedure :: set_state => set_state_impl
    end type Neuron

    !------------------!------------------------------------------------------------------------
    ! Type definitions !
    !------------------!
    type, abstract :: Connection
        class(Neuron), pointer, private :: input_neuron
        class(Neuron), pointer, private :: output_neuron
        real, private                   :: weight

        contains

            procedure :: adjust_weight     => adjust_weight_impl

            ! Getters and setters    
            procedure :: get_input_neuron  => get_input_neuron_impl
            procedure :: get_output_neuron => get_output_neuron_impl
            procedure :: get_weight        => get_weight_impl

    end type Connection

    type, extends(Connection) :: IntervalConnection
       contains
          procedure :: pass_signal => pass_signal_impl
    end type IntervalConnection

    !------------!------------------------------------------------------------------------------
    ! Interfaces !
    !------------!
    interface Connection
        module procedure new_connection
    end interface Connection

    contains
    !------------------------!------------------------------------------------------------------
    ! Method implementations !
    ! -----------------------!

        !--------------!
        ! class Neuron !
        !--------------!
        ! TODO smazat
        function get_state_impl(this) result(state)
            class(Neuron), intent(in) :: this
            real                      :: state

            state = this%state
        end function get_state_impl

        ! TODO smazat
        function set_state_impl(this, new_state) result(ret_this)
            class(Neuron), target  :: this
            real, intent(in)       :: new_state
            class(Neuron), pointer :: ret_this

            ret_this   => this
            this%state = new_state
        end function set_state_impl

        !------------------!
        ! class Connection !
        !------------------!
        subroutine adjust_weight_impl(this, added_value)
            class(Connection), intent(inout) :: this
            real, intent(in)                 :: added_value

            this%weight = this%weight + added_value
        end subroutine adjust_weight_impl

        !--------------------------!
        ! class IntervalConnection !
        !--------------------------!
        subroutine pass_signal_impl(this)
            ! TODO dokoncit
            class(IntervalConnection), intent(in) :: this
            real :: a
            class(Neuron), pointer :: dummy

            a=this%weight * this%input_neuron%get_state()

            dummy => this%output_neuron%set_state(5.0)

            !this%output_neuron%set_state(this%weight * this%input_neuron%get_state())
        end subroutine pass_signal_impl

        !--------------!------------------------------------------------------------------------
        ! Constructors !
        !--------------!
        function new_connection(this, input_neuron, output_neuron, weight) result(ret_this)
            class(Connection), target  :: this
            class(Connection), pointer :: ret_this
            class(Neuron), pointer     :: input_neuron
            class(Neuron), pointer     :: output_neuron
            real, intent(in)           :: weight

            ret_this           => this
            this%input_neuron  => input_neuron
            this%output_neuron => output_neuron
            this%weight        = weight
        end function new_connection

        !-------------------!-------------------------------------------------------------------
        ! Getters & Setters !
        !-------------------!
        function get_input_neuron_impl(this) result (input_neuron)
            class(Connection), target, intent(in) :: this
            class(Neuron), pointer                :: input_neuron

            input_neuron => this%input_neuron
        end function get_input_neuron_impl

        function get_output_neuron_impl(this) result (output_neuron)
            class(Connection), target, intent(in) :: this
            class(Neuron), pointer                :: output_neuron

            output_neuron => this%output_neuron
        end function get_output_neuron_impl

        function get_weight_impl(this) result (weight)
            class(Connection), intent(in) :: this
            real                          :: weight

            weight = this%weight
        end function get_weight_impl
end module Connection_mod

program a
    use Connection_mod

    type(Neuron), target :: n1
    type(Neuron), target :: n2

    type(Neuron), pointer :: n1_p
    type(Neuron), pointer :: n2_p

    type(IntervalConnection) :: con

    n1_p => n1
    n2_p => n2
    con = IntervalConnection(n1_p, n2_p, 5.0)

end program a

Solution

  • The function you created as a constructor takes four arguments

    function new_connection(this, input_neuron, output_neuron, weight)
    

    but you call it with three arguments

    class(IntervalConnection) :: con
    
    con = IntervalConnection(n1_p, n2_p, 5.0)
    

    I moved the assignment out. It is not strictly necessary.


    Therefore the generic resolution (TKR) cannot be successful and the default constructor will be tried.

    And you also overloaded the Constructor or Connection, but then you call IntervalConection(). These are different!

    You probably misunderstood how a constructor works with the arguments and return values. There is no place for any this argument. A constructor is NOT a type-bound procedure. It is not inherited. But the child connection can call the parent constructor if needed. Sometimes you want that, sometimes not. Notice the returned value is type, not class!

    function new_interval_connection(input_neuron, output_neuron, weight) result(ret)
            type(IntervalConnection) :: ret
            class(Neuron), pointer     :: input_neuron
            class(Neuron), pointer     :: output_neuron
            real, intent(in)           :: weight
    
            ret%input_neuron  => input_neuron
            ret%output_neuron => output_neuron
            ret%weight        = weight
    end function new_interval_connection
    

    You want to create an instance of make the constructor for IntervalConnection, not for Connection, as you tried

    interface IntervalConnection
        module procedure new_interval_connection
    end interface Connection
    
    con = IntervalConnection(n1, n2, 5.0)