Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29273 Discussions

is there class prototype or static method in IVF?

An_N_1
New Contributor I
3,358 Views

 

As in my mind, type bound procedure with NOPASS attribute, the method is a static method, and can be referred to using the name of the class prototype. Otherwise, with PASS attribute the method is an instance method, and is referred to using the name of the particular instance of the class.

In intel fortran, it seems not support the using of class prototype to invoke nopass procedure. We must define or allocate a instance to call PASS or NOPASS procedures.

Before an allocatable derived type variable is allocated, its nopass procedure can be called correctly if no runtime check of null pointer and allocatable array references. Is it a advisable way to do that kind of things?

0 Kudos
1 Solution
IanH
Honored Contributor III
3,358 Views

I think the inappropriate mapping of terminology from other languages (and perhaps a requirement to fit in the .NET framework, in Lahey's case) onto Fortran is what initially lead things astray here.

This is more than a bit subjective, but my view is that in the design of standard Fortran, the syntax `object%binding(...)` is principally about runtime dispatch to a particular procedure based on the dynamic type of the object.  There are some namespace nicety aspects to that syntax as well, but they are secondary to that dynamic dispatch capability.

That dynamic dispatch capability applies regardless of whether the binding is PASS or NOPASS - those attributes are more just conveniences to arrange the call for the underlying procedure interface. 

To do dynamic dispatch based on dynamic type of an object - you need to have a valid object. 

The concept "static method of a class" has nothing to do with dynamic dispatch.  The subject type is known at compile time, hence the subject procedure is known.  Putting accessibility aside for a moment, then to invoke that procedure... you just invoke it by its name.

That `object%binding` is principally about dynamic dispatch also arises with the common question "how do I call the procedure referenced by a binding in the abstract parent of a type - the compiler won't let me do object%parent%binding(...)".  Again, the parent type of a particular type is fixed, hence the procedure that the binding of an object of the parent type will reference is fixed, hence there's no need to do dynamic dispatch - accessibility aside you just invoke the procedure by its name.

The `object%binding(...)` syntax can obviously be used in cases where the dispatch can be statically determined (say if the object is not polymorphic), but I think from a conceptual point of view this capability in the language should almost be regarded as inadvertent, rather than the principal design intent of the syntax. 

(Practically, if there's a passed object then there will also, typically, be the need to construct a polymorphic descriptor or similar for the passed object too, which may have performance implications as mentioned above.  I interpret the inability to avoid the construction of this descriptor, in a language that has performance as an important design criteria, as further evidence around design intent.)

From the point of view of the way the language handles accessibility aspects, accessibility in Fortran is based around modules, not around types.  Further, unlike other languages, procedures don't belong to types - procedures are instead referenced by bindings in types.  It is quite possible for the one procedure to be referenced by bindings in completely unrelated types.

Consequently, Fortran doesn't have an identical equivalent to a "static method of a class".  The closest approximation isn't a NOPASS binding, it is simply an accessible procedure from the same module that defined the type.

The above isn't a justification of the language design, it is just a description of the philosophy and concepts that I interpret, retrospectively, to have informed the design.

View solution in original post

0 Kudos
17 Replies
FortranFan
Honored Contributor III
3,358 Views

Perhaps you can further elaborate on your question with concrete examples because your questions and concerns are not fully clear to me.  As you would know well, type-bound procedures and their uses are intended to facilitate object-oriented programming (OOP) and as the vast body of literature on object-oriented techniques show, proper analysis and design are crucial [one example, structure of arrays (SoA) vs array of structures (AoS)] for efficient implementation.  Almost all the established "good practices" for OOA, OOD, and OOP would largely extend to Fortran as well, so you may want to review OO literature closely, if general efficiency of OO implementations is what you're asking about.  When it comes specifically to Fortran, books mentioned by Dr Fortran in his blog can be useful.

On some of your points about procedures with NOPASS and PASS attributes, note the snippet below shows several allowed uses for them in the standard but as to whether they are appropriate and efficient for your needs is something you would know best given your code as well as your OO analysis and design on the program.  Some seem to think the polymorphic requirement with the PASS attribute of type-bound procedures incurs some performance penalty and prefer traditional procedure invocations where the dummy argument of the type is not polymorphic (TYPE vs CLASS); I prefer otherwise. 

module m

   implicit none

   private

   type, public :: t
      private
      integer :: m_i = 42
   contains
      private
      procedure, nopass, public :: sub
      procedure, pass(this), public :: i
   end type t

   public :: sub
   public :: i

contains

   subroutine sub()

      print *, " from sub: hello world!"

      return

   end subroutine sub

   function i(this) result(ival)

      class(t), intent(in) :: this
      !.. function result
      integer :: ival

      ival = this%m_i

      return

   end function i

end module m
program p

   use m, only : t, sub, i

   implicit none

   type(t) :: foo

   call sub()

   print *, " in main - i(foo) returns ", i(foo)
   print *, " in main - foo%i() returns ", foo%i()

   call foo%sub()

   stop

end program p
  from sub: hello world!
  in main - i(foo) returns           42
  in main - foo%i() returns           42
  from sub: hello world!

 

0 Kudos
Steven_L_Intel1
Employee
3,358 Views

I'll also comment that Intel Fortran supports what the Fortran standard specifies. We don't go adding features in this area.

0 Kudos
An_N_1
New Contributor I
3,358 Views

Steve should know what I want to ask about, and I quite understand Steve about not adding extra features in oop.

In Mr. FortranFan's example, sub is a nopass procedure which make it seems to be a static method. What i want to know is how to call sub without a type instant while sub is a public procedure and a private subroutine.

In some situations, we may want to call a static method before a instant is allocated.

take following code as example:

type(t), allocatable :: foo
call foo % sub

if set nocheck pointer compile option, above code works well. is it a advisable way?

In some other fortran compiler, it can be write like:

call t % sub

which is not allowed by IVF. So I want to know if there is a safe way to do so, or it is absolutely not adviced to do so in this way in IVF. Of course it does not mean that i trend to encourage IVF to support extra features in addition to fortran standard.

0 Kudos
Arjen_Markus
Honored Contributor II
3,358 Views

How about defining a parameter of that type instead of a variable? The parameter could be given a name that makes clear what its purpose in life is and you avoid tricks with compiler options that may actually be very useful for checking the rest of the program.

0 Kudos
Steven_L_Intel1
Employee
3,358 Views

Actually, I am not certain what you are asking. Please provide a short but complete example that works in some other compiler but not in Intel Fortran. You also mentioned /check:pointer - we have had bugs in that regard so perhaps that's related.

0 Kudos
An_N_1
New Contributor I
3,358 Views

Sorry for my poor language ability. perhaps computer language will help to make more clear. 

Codes in last article follows FortranFan's example. Here I give a independent version.

In some situations, there may be a reqiure to call procedures before a instant is allocated. Of couse it is not essential, and can be realized by many other ways.

What I want to know is : is it rational in IVF? Or it should be avoided?

    module m
    
    implicit none
    
        type :: typ_Exmp
        contains
            procedure, nopass :: static_method
            procedure, pass   :: instance_method
        end type typ_Exmp
    
    contains
    
        subroutine static_method (arg)
        integer :: arg
        end subroutine
        
        subroutine instance_method ( this, arg )
        class (typ_Exmp) :: this
        integer :: arg
        end subroutine
    
    
    end module


program oop_test

use m

    type(typ_exmp), allocatable :: exmp
    type(typ_exmp) :: exmp_instance

    integer i
    
    call exmp % static_method (i)               !it works. But with option check:pointer, get a runtime error.
    
    call exmp_instance % instance_method (i)    !it works, of course. which is comply with standard
    
    call typ_exmp % static_method (i)           !compile error, of course it is not supported. 
                                                !Some compiler extend extra features support that, for example Lahey Fortran.
                                                !It does not mean that I trend to appeal IVF to support extra features in addition to standard.

end program

0 Kudos
Steven_L_Intel1
Employee
3,358 Views

Thanks for the example.

The call to exmp%static_method violates the following rule in the standard: "The data-ref in a procedure-designator shall not be an unallocated allocatable variable or a pointer that is not associated." (F2008 12.5.1p2)

The call to typ_exmp%static_method, as you say, is non-standard. Which Lahey Fortran supports this? The old Fujitsu one or the gfortran one?  That's an unfortunate extension as one can do this:

type(some_other_type) :: typ_exmp

Now when you call typ_exmp%static_method, which one do you mean?

0 Kudos
Andrew_Smith
Valued Contributor I
3,358 Views

Since the typ_exmp variable is not polymorphic there is no decision to make. This potential "new feature" would need such a limitation.

It would be nice to have static parameter variables accessible in this way too (asumming it was made legal to declare them).

0 Kudos
Arjen_Markus
Honored Contributor II
3,358 Views

You can have parameters of a derived type and call static methods via them:

module param
    type myclass
        integer :: x
    contains
        procedure, public, nopass :: check
    end type

    type(myclass), parameter :: px = myclass(1)
contains
subroutine check
    write(*,*) 'Check'
end subroutine check
end module param

program test_param
    use param

    call px%check
end program test_param

Unless I misunderstand what you mean ;)

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,358 Views

Why not prefix your static methods of a type with the type name

    module m
    
    implicit none
    
        type :: typ_Exmp
        contains
            procedure, nopass :: typ_Exmp__static_method
            procedure, pass   :: instance_method
        end type typ_Exmp
    
    contains
    
        subroutine  typ_Exmp__static_method (arg)
        integer :: arg
        end subroutine
        
        subroutine instance_method ( this, arg )
        class (typ_Exmp) :: this
        integer :: arg
        end subroutine
    
    
    end module


program oop_test

use m

    type(typ_exmp), allocatable :: exmp
    type(typ_exmp) :: exmp_instance

    integer i
    
    call exmp %  typ_Exmp__static_method (i)               !it works. But with option check:pointer, get a runtime error.
    
    call exmp_instance % instance_method (i)    !it works, of course. which is comply with standard
    
    call  typ_Exmp__static_method (i)           
                                                !Some compiler extend extra features support that, for example Lahey Fortran.
                                                !It does not mean that I trend to appeal IVF to support extra features in addition to standard.


Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,358 Views

Or, without the prefix

use m, YourLocalName => static_method

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor III
3,358 Views

An N. wrote:

.. Codes in last article follows FortranFan's example. Here I give a independent version.

In some situations, there may be a reqiure to call procedures before a instant is allocated. Of couse it is not essential, and can be realized by many other ways.

What I want to know is : is it rational in IVF? Or it should be avoided ..

WD 1529-1 J3/10-007r1 (November 2010) document for Fortran 2008 standard says in 2.4.9.2, "An unallocated allocatable variable shall not be referenced or defned."  I'm not sure but does the standard leave it up to the processor to decide on the response when such a thing happens.  Few might agree with me but I personally would read a statement on line 35 in the code snippet in Message #7 such as "call exmp%static_method(i)" to imply a reference to an unallocated allocatable variable, even though NOPASS attribute might suggest otherwise.

It seems several compilers including Lahey (don't know for sure, but I assume as much from OP's comments), Intel Fortran, and also gfortran allow and execute such code when run-time checks are not brought into play.  As to whether this is "rational or to be avoided" is probably a matter of preference.  By the way, what would coders expect next!?  Could they then also want to be able to do "call exmp%static_method( exmp%i )" where i might be a component of the type with some default initialization?

I personally would avoid such things, but that is just my opinion.  Good question though, probably worth discussing at comp.lang.fortran.

0 Kudos
Steven_L_Intel1
Employee
3,358 Views

See post #8. The standard is clear on this.

0 Kudos
FortranFan
Honored Contributor III
3,358 Views

Steve Lionel (Intel) wrote:

See post #8. The standard is clear on this.

Steve,

In Message #8, you state, "The call to exmp%static_method violates the following rule in the standard: "The data-ref in a procedure-designator shall not be an unallocated allocatable variable or a pointer that is not associated." (F2008 12.5.1p2)."  But Intel Fortran and gfortran (and perhaps Lahey compiler too) allow such usage; Intel Fortran only raises an exception at run-time if /check:pointer is in effect.  So do you then envision Intel Fortran enforcing the standard on this matter only via /check:pointer option?  

module m

   implicit none

   private

   type, public :: t
      private
   contains
      private
      procedure, nopass, public :: sub
   end type t

contains

   subroutine sub()

      print *, " from sub: hello world!"

      return

   end subroutine sub

end module m
program test

   use m, only : t

   type(t), allocatable :: foo

   call foo%sub()

   stop

end program
  from sub: hello world!
Press any key to continue . . .

 

0 Kudos
Steven_L_Intel1
Employee
3,358 Views

This is a requirement on the programmer, since it is not a numbered syntax rule or constraint. The standard is full of such things. Run-time behaviors, in particular, are not required to be checked. 

0 Kudos
An_N_1
New Contributor I
3,358 Views

Thanks for all !

I fully understand it is not supported by standard. May be should be avoided by other realization.

for Steve, I have had used Lahey fortran for windows, and turned to IVF for years.

Such kind of using can be referenced on Lahey's web help:

http://www.lahey.com/docs/lfenthelp/NLMOvUsMethods.htm

http://www.lahey.com/docs/lfenthelp/NLMOvElmethods.htm

 

As I noticed Lahey extents OOP features much more, It does not mean that I think it is key features.

0 Kudos
IanH
Honored Contributor III
3,359 Views

I think the inappropriate mapping of terminology from other languages (and perhaps a requirement to fit in the .NET framework, in Lahey's case) onto Fortran is what initially lead things astray here.

This is more than a bit subjective, but my view is that in the design of standard Fortran, the syntax `object%binding(...)` is principally about runtime dispatch to a particular procedure based on the dynamic type of the object.  There are some namespace nicety aspects to that syntax as well, but they are secondary to that dynamic dispatch capability.

That dynamic dispatch capability applies regardless of whether the binding is PASS or NOPASS - those attributes are more just conveniences to arrange the call for the underlying procedure interface. 

To do dynamic dispatch based on dynamic type of an object - you need to have a valid object. 

The concept "static method of a class" has nothing to do with dynamic dispatch.  The subject type is known at compile time, hence the subject procedure is known.  Putting accessibility aside for a moment, then to invoke that procedure... you just invoke it by its name.

That `object%binding` is principally about dynamic dispatch also arises with the common question "how do I call the procedure referenced by a binding in the abstract parent of a type - the compiler won't let me do object%parent%binding(...)".  Again, the parent type of a particular type is fixed, hence the procedure that the binding of an object of the parent type will reference is fixed, hence there's no need to do dynamic dispatch - accessibility aside you just invoke the procedure by its name.

The `object%binding(...)` syntax can obviously be used in cases where the dispatch can be statically determined (say if the object is not polymorphic), but I think from a conceptual point of view this capability in the language should almost be regarded as inadvertent, rather than the principal design intent of the syntax. 

(Practically, if there's a passed object then there will also, typically, be the need to construct a polymorphic descriptor or similar for the passed object too, which may have performance implications as mentioned above.  I interpret the inability to avoid the construction of this descriptor, in a language that has performance as an important design criteria, as further evidence around design intent.)

From the point of view of the way the language handles accessibility aspects, accessibility in Fortran is based around modules, not around types.  Further, unlike other languages, procedures don't belong to types - procedures are instead referenced by bindings in types.  It is quite possible for the one procedure to be referenced by bindings in completely unrelated types.

Consequently, Fortran doesn't have an identical equivalent to a "static method of a class".  The closest approximation isn't a NOPASS binding, it is simply an accessible procedure from the same module that defined the type.

The above isn't a justification of the language design, it is just a description of the philosophy and concepts that I interpret, retrospectively, to have informed the design.

0 Kudos
Reply