views:

49

answers:

1

in fortran, you can pass a function/subroutine A as an argument to another function/subroutine B, but can you store A for later retrieval and use?

for example, this is allowed in C

int foo(float, char, char) { /*whatever*/};

int (*pointerToFunction)(float, char, char);
pointerToFunction = foo;

In Fortran you can pass a subroutine as an argument

subroutine foo
! whatever
end subroutine foo

subroutine bar(func)
    call func
end subroutine bar

program x

    call bar(foo)

end program

but how can you store the address of foo in a similar way to C ?

+1  A: 

Starting from so-called "Fortran 2003" (ISO/IEC 1539-2004) procedure pointers is a part of the Fortran language. It's definitely of the major new features of Fortran language.

Usage example from Fortran Wiki.


Stefano, you mentioned strategy design pattern. In Fortran 2003 you can use pure OOP way to implement it (without procedure pointers). Offhand example:

strategies.f90

module strategies

  implicit none

  private

  public :: strategies_transportation_strategy, &
            strategies_by_taxi_strategy, &
            strategies_by_bus_strategy

  type, abstract :: strategies_transportation_strategy
  contains
    procedure(transportation_strategy_go), deferred :: go
  end type strategies_transportation_strategy

  type, extends(strategies_transportation_strategy) :: strategies_by_taxi_strategy
  contains
    procedure :: go => strategies_by_taxi_strategy_go
  end type strategies_by_taxi_strategy

  type, extends(strategies_transportation_strategy) :: strategies_by_bus_strategy
  contains
    procedure :: go => strategies_by_bus_strategy_go
  end type strategies_by_bus_strategy

  abstract interface
    subroutine transportation_strategy_go(this)
      import strategies_transportation_strategy
      class(strategies_transportation_strategy), intent(in) :: this
    end subroutine transportation_strategy_go
  end interface

  contains

    subroutine strategies_by_taxi_strategy_go(this)
      class(strategies_by_taxi_strategy), intent(in) :: this

      print *, "We are using taxi."

    end subroutine strategies_by_taxi_strategy_go

    subroutine strategies_by_bus_strategy_go(this)
      class(strategies_by_bus_strategy), intent(in) :: this

      print *, "We are using public transport."

    end subroutine strategies_by_bus_strategy_go

end module strategies

vehicles.f90

module vehicles

  use strategies

  implicit none

  private

  public :: vehicles_vehicle, &
            vehicles_taxi, &
            vehicles_bus

  type, abstract :: vehicles_vehicle
    private
    class(strategies_transportation_strategy), allocatable :: transportation_strategy
  contains
    procedure :: set_transportation_strategy => vehicle_set_transportation_strategy
    procedure :: go => vehicle_go
  end type vehicles_vehicle

  type, extends(vehicles_vehicle) :: vehicles_taxi
  contains
    procedure :: init => taxi_init
  end type vehicles_taxi

  type, extends(vehicles_vehicle) :: vehicles_bus
  contains
    procedure :: init => bus_init
  end type vehicles_bus

  contains

    subroutine vehicle_go(this)
      class(vehicles_vehicle), intent(in) :: this

      call this%transportation_strategy%go()

    end subroutine vehicle_go

    subroutine vehicle_set_transportation_strategy(this, new_transportation_strategy)
      class(vehicles_vehicle), intent(inout) :: this
      class(strategies_transportation_strategy), intent(in) :: new_transportation_strategy

      if (allocated(this%transportation_strategy)) then
        deallocate (this%transportation_strategy)
      end if

      allocate (this%transportation_strategy, source=new_transportation_strategy)

    end subroutine vehicle_set_transportation_strategy

    subroutine taxi_init(this)
      class(vehicles_taxi), intent(out) :: this

      type(strategies_by_taxi_strategy) :: by_taxi_strategy

      call this%set_transportation_strategy(by_taxi_strategy)

    end subroutine taxi_init

    subroutine bus_init(this)
      class(vehicles_bus), intent(out) :: this

      type(strategies_by_bus_strategy) :: by_bus_strategy

      call this%set_transportation_strategy(by_bus_strategy)

    end subroutine bus_init

end module vehicles

main.f90

program main

  use vehicles

  implicit none

  type(vehicles_taxi) :: taxi
  type(vehicles_bus) :: bus

  call taxi%init()
  call bus%init()

  call taxi%go()
  call bus%go()

end program main

At least works using gfortran 4.6 (20100925).

kemiisto
I was worried about that. Ok, I can live with it. I have the feeling that ifort supports it as well.
Stefano Borini
unrelated note. Do you work at CTCC ?
Stefano Borini
@Stefano: i will check ifort in the evening. And yes, I'm PhD student at University of Oslo, CTCC. However I do some mass-spectrometry and quantum chemistry calculations and nothing related to Dalton.
kemiisto
ifort 11.1 20100203: vehicles.f90(48): error #5415: Feature not yet implemented: SOURCE=polymorphic_expression =(
kemiisto
cool :) say hi to Trygve and Thomas :)
Stefano Borini