- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I am trying to look for a method where I can apply a certain procedure consistently to all components of a derived type. It can be anything where I need apply the same operations to all components of a derived type. Now, when I later on add an extra component to the derived type, I need likewise to adopt the procedures to incorporate that change.
Imagine this very simple scenario where I need to initialize all my components to a certain value.
subroutine reset(this,val) type(t_mod) :: this real :: val do i = this% size_ this% a(i) = val this% b(i) = val this% c(i) = val enddo end subroutine
Another example is the routine which allocates all components. That likewise requires a similar approach as above.
If I later add a component "d" to my "t_mod" declared type I need manually to go to the reset subroutine and introduce the
"this% d(i) = val" ..
How can I abstract this so my procedure "reset" is executed consistently to all components of the derived type.
In my code I have many of such subroutines which requires operations on all components. At this time I am getting frustrated that whenever I add an extra component to my t_mod", I need to go through all these routine to add that extra component.
Is it possible to find an abstraction to this in Fortran or mixing with c/c++
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is no feature in Fortran to iterate through components of a derived type. You can, of course, extend a generic procedure to operate on an extended type, with the new procedure processing only the new components and calling the same generic to handle the parent, but this still requires you to write the code.
If you used an array instead of separate components, this would be easy, but I'm sure you already thought of that. (And no, different elements of an array can't be different types.)
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is no feature in Fortran to iterate through components of a derived type. You can, of course, extend a generic procedure to operate on an extended type, with the new procedure processing only the new components and calling the same generic to handle the parent, but this still requires you to write the code.
If you used an array instead of separate components, this would be easy, but I'm sure you already thought of that. (And no, different elements of an array can't be different types.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Steve,
It is good to have this confirmed.
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
AT90
Depending on how you externally access the components, you may be able to use a single 2D array:
this%components(componentNumber, indexWithinComponent)
then the init all becomes
this%components = val ! all components, all values
integer, parameter :: a=1
...
this%components(a,:)=val ! all values of component a
As to if you organize the indices the other way around, this is an optimization issue.
You may need to augment the component names slightly to avoid name collisions.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
AT90
if your components are of different types and arrays are not a solution, you may consider a polymorphic container instead:
module m implicit none ! Element type (array valued) type :: Element_type class(*), dimension(:), allocatable :: arr end type ! Container type type :: Container_type type(Element_type), dimension(:), allocatable :: elems contains procedure :: create => Container_create procedure :: reset => Container_reset procedure :: scale => Container_scale procedure :: print => Container_print end type contains ! Constructor subroutine Container_create(this, size) class(Container_type), intent(out) :: this integer, intent(in) :: size ! Allocate elements allocate(this%elems(4)) allocate(real :: this%elems(1)%arr(size)) allocate(integer :: this%elems(2)%arr(size)) allocate(complex :: this%elems(3)%arr(size)) allocate(real :: this%elems(4)%arr(size)) ! ... add more elements in future ... end subroutine ! Scalar assignment subroutine Container_reset(this, val) class(Container_type), intent(inout) :: this real, intent(in) :: val integer :: i do i = 1, size(this%elems) select type (arr => this%elems(i)%arr) type is (integer) arr = floor(val) type is (real) arr = val type is (complex) arr = cmplx(val, 0.0) end select end do end subroutine ! Scalar multiplication subroutine Container_scale(this, val) class(Container_type), intent(inout) :: this real, intent(in) :: val integer :: i do i = 1, size(this%elems) select type (arr => this%elems(i)%arr) type is (integer) arr = floor(arr * val) type is (real) arr = arr * val type is (complex) arr = arr * val end select end do end subroutine ! Print to terminal subroutine Container_print(this) class(Container_type), intent(in) :: this integer :: i do i = 1, size(this%elems) write (*,"(a,i0,a)") 'element no.', i, ':' select type (arr => this%elems(i)%arr) type is (integer) write (*,"(i0)") arr type is (real) write (*,"(g0)") arr type is (complex) write (*,"('(',g0,x,g0,')')") arr end select end do end subroutine ! ... add more operations here .... end module program p use m implicit none type(Container_type) :: myContainer ! Test call myContainer%create(10) call myContainer%reset(9.99) call myContainer%scale(0.1) call myContainer%print() end program
Of course in any case the programmer has to write out the elemental operations between all the supported types of components (here: container elements), but new components can then be added with a single line in the constructor.
If one needs to mix array-valued and scalar elements etc., one could do so by making the Element_type abstract and extend to ArrayElement_type, ScalarElement_type and so on.
Kind regards
Ferdinand
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page