- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The restrictions for a dummy argument which is not present are in 18-007 (the F2018 standard document) on 15.5.2.12p3 where I don't see any restriction. Your code compiles with nagfor, with gfortran and with PGI fortran.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My hunch too is your code conforms to the current standard (Fortran 2008).
I think it's a bug in Intel Fortran with a basic aspect introduced in the language starting with Fortran 90 involving OPTIONAL dummy arguments but manifesting in the compiler with the feature of polymorphic dummy arguments introduced with Fortran 2003.
You may want to submit a support request at the Intel OSC: https://supporttickets.intel.com/?lang=en-US
In the meantime, you may want to look into working around the segmentation fault by doing something "silly" but functional like so:
subroutine sub1(a, p, c) class(t), intent(in) :: a type(t), optional, intent(out) :: p integer, pointer, optional, intent(out) :: c if ( present(p) .and. present(c) ) then call sub2(a, p, c) else if ( present(p) ) then call sub2(a, p=p) else if ( present(c) ) then call sub2(a, c=c) else call sub2(a) end if end subroutine sub1
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Or a simpler variant of a workaround focusing on the polymorphic dummy argument in sub2 may also suffice:
subroutine sub1(a, p, c) class(t), intent(in) :: a type(t), optional, intent(out) :: p integer, pointer, optional, intent(out) :: c if ( present(p) ) then call sub2(a, p, c) else call sub2(a, c=c) end if end subroutine sub1
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FortranFan wrote:
Or a simpler variant of a workaround focusing on the polymorphic dummy argument in sub2 may also suffice:
subroutine sub1(a, p, c) class(t), intent(in) :: a type(t), optional, intent(out) :: p integer, pointer, optional, intent(out) :: c if ( present(p) ) then call sub2(a, p, c) else call sub2(a, c=c) end if end subroutine sub1
Yes, this one is obvious, but I think that was the main point of the discussion that the segmentation fault is only present of the optional intent(out) is class(t) instead of type(t).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Martin wrote:
.. in the real case the type of x encapsulated in t is class(*) instead of integer. And with class(*) generic interfaces often become impossible.
.. Being rather new to oop-fortran I find it sometimes difficult to choose between the use of type or class in such cases as these intent(out) return values ..
Object-oriented analysis and design *before* doing any object-oriented programming seems to help in such matters.
Don't know if this is relevant to OP's real code, but it may prove easier to work with code if as a code design consideration, one can avoid unlimited poiymorphic objects, or at least such components in derived types, and the use of allocatable attribute is preferred over pointer.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FortranFan wrote:At this point, it is just playing around, trying to find a good way to implement general container classes such as sets, maps etc. class(*) seems to be the only way to achieve this without any quirky stuff. This example is derived from a lookup type routine. The pointer is used to avoid potentially large copies if complex objects are stored. Otherwise allocatable makes life much easier. In particular move_alloc allows fast transfer of objects into and from containers. All in all current fortran does not seem to be very suitable for such general purpose classes, but it works ok. Regarding type versus class: I think this has not much to do with oop design in general, but is something fortran specifc. Using type signals that routines and derived types are not really intended to be extended in the future, and might be a little more performant. Or are there any other motivations for using type over class?
Object-oriented analysis and design *before* doing any object-oriented programming seems to help in such matters.
Don't know if this is relevant to OP's real code, but it may prove easier to work with code if as a code design consideration, one can avoid unlimited poiymorphic objects, or at least such components in derived types, and the use of allocatable attribute is preferred over pointer.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'll just throw in the general observation that anytime you defer decisions to run-time, you have a performance penalty. In the case of passing an item declared TYPE to one declared CLASS, there can be a lot of overhead setting up the "class descriptor" information for the call.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If I have some spare time, I will check produced assembler to get a feeling for the overhead of going from type to class. I was already (and still are) wondering about this overhead and how the compiler is handling a routine like:
sub(...)
type(t) :: x
call x%sub1(...)
call x%sub2(...)
call x%sub3(...)
end sub
As sub[123] are type bound procedures, argument x passed to these subroutines is declared class(t). So is the class header setup thrice or is the compiler able to optimise it to just one setup, ideally at creating time of x.
I am also a bit worried (performance wise) that transforming old-style ADT without type-bound procedures into a proper class will degrade performance in critical code places. As the self/this argument needs to be declared as class, this overhead cannot be avoided. Once I thought that using type(t) in declaration allows the compiler to resolve calls at compile-time and to bypass v-table access and potential pointer-chasing. But if type t is in its own module and IPO is not used, this is not going to happen I guess.
Anyway, time-critical code where oop features are to be avoided tend to account only for a minor amount of code even in numerical applications, whereas organisational stuff (which can easily run at half the speed without much penalty overall) usually takes up most of the code. Moreover, having generic (but slow) containers using class(*) features at hand makes life easier even for time critical pieces of code during prototyping/experimenting phase. So I am quite happy at the state of fortran.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Martin wrote:
As sub[123] are type bound procedures, argument x passed to these subroutines is declared class(t). So is the class header setup thrice or is the compiler able to optimise it to just one setup, ideally at creating time of x.
I am also a bit worried (performance wise) that transforming old-style ADT without type-bound procedures into a proper class will degrade performance in critical code places. As the self/this argument needs to be declared as class, this overhead cannot be avoided. Once I thought that using type(t) in declaration allows the compiler to resolve calls at compile-time and to bypass v-table access and potential pointer-chasing. But if type t is in its own module and IPO is not used, this is not going to happen I guess.
Yes, in your example above the compiler should definitely be able to avoid a vtable call (no matter if the type t is implemented in a separate module or not). But: The compiler still needs to insert a bit of code for converting TYPE to CLASS (for all three calls, unless the compiler is so clever to optimize it into a single conversion).
If, on the other hand, x is declared as class(t), then you need a vtable lookup, but no conversion. Not sure which variant is more performant in the end.
Cheers,
Janus
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Martin wrote:
.. Regarding type versus class: I think this has not much to do with oop design in general, ..
I think otherwise, the decision to declare a dummy argument as TYPE or CLASS as in the optional argument p in the sub1 procedure of the original post is about the use of polymorphism with that function parameter. Object-oriented analysis (OOA) and design (OOD), if done diligently, can help bring considerable discipline and provide guidance toward employing the OO features of polymorphism and inheritance *only* as needed in conjunction with the goals and requirements of one's code, and not willy-nilly as many who are starting off with OO or get enamored by it are wont to do.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FortranFan wrote:
I think otherwise, the decision to declare a dummy argument as TYPE or CLASS as in the optional argument p in the sub1 procedure of the original post is about the use of polymorphism with that function parameter. Object-oriented analysis (OOA) and design (OOD), if done diligently, can help bring considerable discipline and provide guidance toward employing the OO features of polymorphism and inheritance *only* as needed in conjunction with the goals and requirements of one's code, and not willy-nilly as many who are starting off with OO or get enamored by it are wont to do.
This sounds a bit like the BDUF/waterfall design models. Otherwise careful analysis and avoidance of over-engineering (use components over inheritance) are self-evident. Nevertheless, I still would like to hear some fortran specific advantages of type over class (mainly as used in argument declarations). For example in my case where I have a type t, and a subroutine returning (intent(out)) an object of this type, no matter how carefully I plan and analyse, I might still find out in a couple of months or years, that I wish to extend t and still use existing routines. I can always call sub(x%t) for a variable x of this extended type. But this reads awkwardly. Advantages of using type are performance and improved compile-time type checking and error-analysis. But otherwise? Do you have a concrete-example where type offers (some other kind of) advantage over class?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Martin wrote:
.. Nevertheless, I still would like to hear some fortran specific advantages of type over class (mainly as used in argument declarations). ..
In my findings, given my use of the OO features with mostly non-numerical aspects of coding (though these increasingly appear as important or more compared to hardcore number-crunching) and the relative lack of advancement in Fortran compiler optimizations of code involving derived type components, I'm yet to see any advantages or disadvantages with the use of polymorphic objects beyond compiler-time checking and code readability, maintenance, etc.
In terms of OO capabilities in Fortran involving polymorphism and inheritance (e.g., with type extension), where the language-specific considerations come into play is with another aspect altogether. That is with difficulties in employing the first principle of OO which is encapsulation: Fortran modules only allow PRIVATE and PUBLIC attributes for module entities and a much required *third column* (e.g., internal in Microsoft .NET languages or protected in C++) is missing in Fortran. This really curtails, in my opinion, the development of good code, one is forced to make a lot of things PUBLIC which then defeats encapsulation. But of course this is a separate issue from TYPE/CLASS considerations involving polymorphic objects or not as dummy arguments.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yeah, the current state of private/public is a catastrophe. Almost not usable once a "one type per module" policy is followed, which I mostly do. I have already been considering using a trailing underscore (much like the leading underscore in python, but leading underscores are not allowed) to mark private/protected methods. I like this aspect of python. Compile-time checking of following the rules would not be that crucial in my opinion.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Just my 5 cents from fortran oop in hard core number crunching
- oop is king. It allows to the code to reflect the mathematical logic of special cases and their generalization. With that it offers an enormous amount of flexibility
- 1 type 1 module is a catastrophe. I started with that but the limitations on inheritance and access to "sibs" is a nightmare. Now I am back to putting as many types within an inheritance path into on single module and handle their routines via submodules. However, the function headers must sit in the module ......... so easily +1000 lines per module file.
- for hand-core number crunching the general rule remains: keep the data together. Regarding that oop helps to organize the code but only as a container provider around (huge) arrays of intrinsic types. With that inheritance allows to apply different functions to the same array content again reflecting general and special cases. Unlimited polymorphic pointers to scalars (not arrays) of intrinsic types are a recipe for writing java speed code in fortran if applied on a large scale.
- After almost a decade of fortran programming and having increasingly enjoyed oop, if anyone ask me today which close-to-the-metal language to learn nowadays ....................... c++ (I am just to deep in the mud to change)
Cheers
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Martin wrote:
Almost not usable once a "one type per module" policy is followed, which I mostly do.
That strikes me a crazy policy. What motivates it?
Modules are meant to be packages of related things. If you have procedures supporting two types that need to see into the internals of both types, then that indicates those types are pretty closely related.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
ianh wrote:
Quote:
Martin wrote:
Almost not usable once a "one type per module" policy is followed, which I mostly do.
That strikes me a crazy policy. What motivates it?
As a non-native speaker I might have chosen the wrong wording. I just use one type per module where it makes sense. If types are very closely related or really small, then I have more than one in a module. I use subdirectories to organise packages.
One advantage is that routine names can be kept short. Imagine I have type t which extends type s, and t overloads a routine sub. Keeping both in one module means that I have to choose different names for the two variants. Also I find that smaller files are somewhat easier to navigate. To me, putting all together into a large module is just a tiny bit like spaghetti code on a module level.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
may.ka wrote:
- .. access to "sibs" is a nightmare..
- .. if anyone ask me today which close-to-the-metal language to learn nowadays ....................... c++ (I am just to deep in the mud to change),,
@may.ka,
Can you provide a use case for "sibs" in the kind of compute-heavy coding you do?
What is your definition of a "close-to-the-metal language"?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@FortranFan
The code snippet below implements a matrix class with two sibs, a class of squared symmetric matrices
and a class of factors of squared symmetric matrices. Both are direct offspring of the parent class.
This is because both have different arguments for their initialization thus making the factor a child
of the squared_symmetric doesn't work (without inventing procedure name extensions).
In the current implementation every type sits in its own module. This would not compile because the
sib class "matrix_squared_symmetric_factor" is not know to the class "matrix_squared_symmetric".
As the object of class "matrix_squared_symmetric_factor" is indeed the factor of an object of
class "matrix_symmetric_squared" it can be critical for inversion routines to know whether the
factor has already been calculated (the factor is 2/3 of the whole inversion operation).
This knowledge might be communicated via the pointer association status
In my applications val(:,:) might be of 150,000 x 150,000 or more. Therefore depending on the task it might be
necessary to either keep the factor (and maybe in go into swap) or constantly move memory between the
matrix and its factor.
Module Mod_Matrix_parent Type, abstract :: Matrix_parent Real(kind=8), allocatable :: val(:,:) End type Matrix_parent End Module Mod_Matrix_parent Module Mod_Matrix_Squared_Symmetric Type, extends(Matrix_parent) :: Matrix_Squared_Symmetric Type(Matrix_Squared_Symmetric_Factor), Pointer :: tsfac=>null() contains Procedure, Pass :: Init => SubInit Procedure, Pass :: Invert => SubInvert Procedure, Pass :: Invert1 => SubInvert1 Procedure, Pass :: Invert2 => SubInvert2 End type Matrix_Squared_Symmetric contains Subroutine SubInit(this,RMIn) Class(Matrix_Squared_Symmetric), Intent(inout) :: this Real(kind=8), Intent(In) :: RMIn end Subroutine SubInit Subroutine SubInvert(this) if(associated(this%tsfac)) Then call this%invert1() else call this%invert2() End if end Subroutine SubInvert End Module Mod_Matrix_Full Module Mod_Matrix_Squared_Symmetric_Factor Type, extends(Matrix_parent) :: Matrix_Squared_Symmetric_Factor contains Procedure, Pass :: Init => SubInit End type Matrix_Squared_Symmetric_Factor contains Subroutine SubInit(this,tsin) Class(Matrix_Squared_Symmetric_Factor), Intent(inout) :: this Type(Matrix_Squared_Symmetric), Intent(In) :: tsin end Subroutine SubInit End Module Mod_Matrix_Factor
Close-to-the-metal means that one has(is allowed) to do stuff by hand (eg. memory allocation etc) and with that having some control over what the code will do at run time. As an example, the automatic allocation in f08 is handy, but who knows what the compiler does if an array is copied into another array which has the attribute "allocatable" but has been allocated some zillion lines way. Maybe the compiler will just newly allocate it. In some applications this may induce a slow down which renders the program unusable. In some application one may lose pointer association status. Interpreted languages like R and pyhton (I am only loosely familiar with pyhton) are very handy for tiny quick and dirty tasks but number crunching is still the domain of compiled languages like fortran and c/c++ (maybe julia in the future). When functions become time critical R and python usually resort to routines written in fortran or c/c++. However, I am a scientist on a computer, not a computer scientist ........... so I am happy about any knowledge transfer.
cheers
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@may.ka: Cyclic references of modules would be nice to have in some cases like yours, but unfortunately not allowed (haskell comes to mind for an example of how it should have been). But I guess it could be difficult for traditional build systems to handle cycles. But then taking interface generation and compiling apart would be handy for other reasons as well (e.g. improved parallel compiling).
When looking at submodules from this perspective it seems that this is a rather lame solution to these kind of problems.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page