Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

Fortran Programming Language

g95 procedure pointers as derived-type components


Hi All,

I've been programming in f90/f95 since 1994. I've wanted procedure
pointers for a real long time, and I read on another c.l.f posting
that g95 has them. So, I've written a little test program that
_almost_ compiles. Problem is, how on earth do I provide procedure
pointers to the derived-type constructor?

My code:

module objs

    abstract interface
        function myfunc(i) result(rv)
            integer, intent(in) :: i
            integer :: rv
        end function myfunc
    end interface

    type, public :: BASE_OBJ
        integer :: t
        procedure (myfunc), pointer :: f
    end type BASE_OBJ

    contains

    function x2(ob, i) result (rv)
        type (BASE_OBJ), pointer :: ob
        integer :: i
        integer :: rv
        rv = 2 * ob%t + i
        return
    end function x2

    function x3(ob, i) result (rv)
        type (BASE_OBJ), pointer :: ob
        integer :: i
        integer :: rv
        rv = 2 * ob%t + i
        return
    end function x3

    function make_doubler(j) result(rv)
        type (BASE_OBJ) :: rv
        integer :: j
        rv => BASE_OBJ(j, x2)
    end function make_doubler

    function make_tripler(j) result(rv)
        type (BASE_OBJ) :: rv
        integer :: j
        rv => BASE_OBJ(j, x3)
    end function make_tripler

end module objs

program test
   use objs

   d => make_doubler(5)
   print *, d%f(2)
   t => make_tripler(5)
   print *, t%f(2)

   stop
end program test

Please note that I knew in advance that the syntax here would fail; I
just didn't know what to do... The compiler reports:

C:\>g95 victest.f95
In file victest.f95:36

        rv => BASE_OBJ(j, x2)
                            1
Error: Missing actual argument list in function call to 'x2' at (1)
In file victest.f95:42

        rv => BASE_OBJ(j, x3)
                            1
Error: Missing actual argument list in function call to 'x3' at (1)

C:\>

Any advice?

THANKS!
--vic

    type, public :: BASE_OBJ
        integer :: t
        procedure (integer), pointer :: f
    end type BASE_OBJ
On May 11, 1:36 pm, linuxl4.@gmail.com wrote:

>     type, public :: BASE_OBJ
>         integer :: t
>         procedure (integer), pointer :: f
>     end type BASE_OBJ

I tried this, and the original problem persists. The problem is in the
creation of a BASE_OBJ object via the BASE_OBJ constructor. I do not
know how to pass the procedure pointer to the BASE_OBJ constructor.
Within my function make_doubler(), I attempt to create a BASE_OBJ
entity, which requires passing a pointer to the selected function
(e.g. x2 or x3). I don't know how to do it.

Here's the offending code: the BASE_OBJ type has two components, an
integer and a procedure pointer to a function that returns an integer.
I have a function 'x2' that I want to associate

    function make_doubler(j) result(rv)
        type (BASE_OBJ) :: rv
        integer :: j
        rv => BASE_OBJ(j, x2)
    end function make_doubler

And here's the error I get (it's because 'x2' in the constructor call
is not provided with any parameters). Is there a syntactic literal for
a procedure pointer in the derived-type constructor? Or, can I create
the object in another way?

THANKS.
--v

Hello,

  Even in Fortran 95, it is to my knowledge not possible to use
  a pointer or target as an item within a structure constructor
  for a type with pointer components. I imagine this would extend
  to procedure pointers, in which case the only way - apart from
  default initialization - to provide a target is by component
  resolution:

base_obj%f => my_fun

  Note that in a fully Fortran 2003 conforming implementation it is
  possible to do argument assignment by keyword. Not all components
  need to be addressed. This would make

type(base_obj) :: my_obj

my_obj = base_obj(t=0.0d0)

  legal. Default initialization for non-referenced components is
  kept.

Regards

All right, now we're getting closer. Obviously, I needed a default
initializer in the type declaration. Now, the problem is when I
compile it, I get a different assignment error from g95. I think I'm
getting close here...

C:\>g95 victest.f95
In file victest.f95:36

        rv => BASE_OBJ(t=j)
              1
Error: Pointer assignment target is neither TARGET nor POINTER at (1)

C:\>

The code:

module objs

    abstract interface
        function myfunc(i) result(rv)
            integer, intent(in) :: i
            integer :: rv
        end function myfunc
    end interface

    type, public :: BASE_OBJ
        integer :: t = 0
        procedure (myfunc), pointer :: f => NULL()
    end type BASE_OBJ

    contains

    function x2(ob, i) result (rv)
        type (BASE_OBJ), pointer :: ob
        integer, intent(in) :: i
        integer :: rv
        rv = 2 * ob%t + i
        return
    end function x2

    function x3(ob, i) result (rv)
        type (BASE_OBJ), pointer :: ob
        integer, intent(in) :: i
        integer :: rv
        rv = 2 * ob%t + i
        return
    end function x3

    function make_doubler(j) result(rv)
        type (BASE_OBJ), pointer :: rv
        integer :: j
        rv => BASE_OBJ(t=j)
****** HERE'S WHERE IT FAILS
        rv%f => x2
    end function make_doubler

    function make_tripler(j) result(rv)
        type (BASE_OBJ), pointer :: rv
        integer :: j
        rv => BASE_OBJ(t=j)
        rv%f => x3
    end function make_tripler

end module objs

program test
   use objs

   type (BASE_OBJ), pointer :: d, t

   d => make_doubler(5)
   print *, d%f(2)
   t => make_tripler(5)
   print *, t%f(2)

   stop
end program test

I have implemented the default initialization, and I'm getting a
different error in an assignment statement. This is getting close, I
think <grin>...

The error:

C:\>g95 victest.f95
In file victest.f95:36

        rv => BASE_OBJ(t=j)
              1
Error: Pointer assignment target is neither TARGET nor POINTER at (1)

C:\>

The Code:

module objs

    abstract interface
        function myfunc(i) result(rv)
            integer, intent(in) :: i
            integer :: rv
        end function myfunc
    end interface

    type, public :: BASE_OBJ
        integer :: t = 0
        procedure (myfunc), pointer :: f => NULL()
    end type BASE_OBJ

    contains

    function x2(ob, i) result (rv)
        type (BASE_OBJ), pointer :: ob
        integer, intent(in) :: i
        integer :: rv
        rv = 2 * ob%t + i
        return
    end function x2

    function x3(ob, i) result (rv)
        type (BASE_OBJ), pointer :: ob
        integer, intent(in) :: i
        integer :: rv
        rv = 2 * ob%t + i
        return
    end function x3

    function make_doubler(j) result(rv)
        type (BASE_OBJ), pointer :: rv
        integer :: j
        rv => BASE_OBJ(t=j)
        rv%f => x2
    end function make_doubler

    function make_tripler(j) result(rv)
        type (BASE_OBJ), pointer :: rv
        integer :: j
        rv => BASE_OBJ(t=j)
        rv%f => x3
    end function make_tripler

end module objs

program test
   use objs

   type (BASE_OBJ), pointer :: d, t

   d => make_doubler(5)
   print *, d%f(2)
   t => make_tripler(5)
   print *, t%f(2)

   stop
end program test

THANKS!
--v

If rv is a pointer (to a scalar object), you need to first have it
point to an existing target, or dynamically allocate it. The structure
constructor will *not* do that for you. Once it *is* allocated,
you use the standard assignment to provide the target with
appropriate values, i.e.

rv = base_obj(t=j)

Again, if the compiler does not yet support the F2003 keyword/optional
parameter syntax, you may need to do

rv%t = j

anyway.

Regards

Vic.Kel@gmail.com wrote:
> ... Problem is, how on earth do I provide procedure
> pointers to the derived-type constructor?

If I read the F2003 (draft) Standard correctly, in particular 4.5.9
C490, it should be possible.

That is, say I have an abstract interface:

    abstract interface
      subroutine mysub (a, b)
        integer :: a, b
      end subroutine
    end interface

and a derived type which contains a procedure pointer:

    type mytype_t
      procedure(mysub), pointer :: pptr
    end type

    type(mytype_t) :: pptrs(5)

G95 lets me write:

    pptrs(1)%pptr => mysub1
    pptrs(2)%pptr => mysub2
    pptrs(3)%pptr => mysub3
    pptrs(4)%pptr => mysub4
    pptrs(5)%pptr => mysub5

This works fine.

According to C490 I should also be able to use a structure constructor
to write:

    pptrs(1) = mytype_t (mysub1)
    pptrs(2) = mytype_t (mysub2)
    pptrs(3) = mytype_t (mysub3)
    pptrs(4) = mytype_t (mysub4)
    pptrs(5) = mytype_t (mysub5)

G95 gives an error message.  ("... Expected 'mysub1' ... to be a VARIABLE").
So my take is that g95 still has a bit to go to properly support the feature.
An email to Andy might be appropriate...

W.

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc