1

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
Eenoku
  • 2,369
  • 2
  • 26
  • 45
  • Which do you think is the "constructor"? Note that `new_connection ` is a subroutine. – francescalus Nov 17 '17 at 23:03
  • @francescalus I've rewritten `new_connection` to be a function - info added to my question together with new problem :-) – Eenoku Nov 17 '17 at 23:09
  • But the interface overrides some `IConnection`, not `IntervalConnection`This looks like a simple typo. – Vladimir F Nov 17 '17 at 23:13
  • @VladimirF Thank you! I've fixed it (the constructor is really supposed to be defined in `Connection` and `IntervalConnection` should just inherit it), but the first error (private variable) persists... – Eenoku Nov 17 '17 at 23:22
  • @VladimirF Ok, I've deleted those unnecessary parts – Eenoku Nov 17 '17 at 23:39
  • Are you trying to call the `new_connection` function? It is part of a generic name called `Connection`. You never reference that generic name in your main program - you reference the structure constructor `IntervalConnection`. In your question body you talk about "inheriting constructors" - as a concept that does not make sense. – IanH Nov 18 '17 at 04:48
  • it was different when I was writing the answer. It wasn't too clear if he calls the child or parent. – Vladimir F Nov 18 '17 at 08:50

1 Answers1

1

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)
Vladimir F
  • 50,383
  • 4
  • 60
  • 96
  • So, your code is valid? And how would you call the constructor then? I don't see any way to call the function `new_connection` with `this` when its the instance I want to create – Eenoku Nov 17 '17 at 23:40
  • Great think would be, if I could call the constructor like this `con = IntervalConnection(n1_p, n2_p, 5.0)`, but I don't know, if its even possible here to do it with my own constructor and not the default one. – Eenoku Nov 17 '17 at 23:41
  • That is the point! The function creates the object, you do not pass it in any way. That's why I deleted the argument. You call it the same way as before. – Vladimir F Nov 18 '17 at 08:39
  • Sorry, I forgot `this` in the argument list. There is NO `this` there! It creates the object from scratch and returns as a function, it does not get it paassed from anywhere. – Vladimir F Nov 18 '17 at 09:10
  • `type(Connection)` isn't allowed: `connection` is an abstract type which cannot be instantiated. – francescalus Nov 18 '17 at 10:54
  • I didn't notice that. The OP himself declared the interface for Connection instead for IntervalConnection. It is actually simpler then. And a part of the code in the answer was taken from the previous messy shape of the question. – Vladimir F Nov 18 '17 at 12:02
  • @VladimirF Thank you for your answer, but I really want to do the constructor of `Connection` and NOT of `IntervalConnection`. I wanted to do the same thing like is described in [this answer](https://stackoverflow.com/a/260755/3801449) for Java. – Eenoku Nov 18 '17 at 18:37
  • @VladimirF Ok, I see my mistake now, constructors can't be inherited... Thank you for your answer! – Eenoku Nov 18 '17 at 18:44
  • You can make a constructor of an abstract class. But it must return an allocatable class and you must allocate it inside the constructor to some child. It is therefore not very useful. You can make also a type-bound subroutine that sets up the value. It wouldn't be a constructor, but it could still be useful. Something like your original design in the first version of the question. – Vladimir F Nov 18 '17 at 19:48