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

TypeCast during runtime possible?

ratzeputz
Beginner
1,926 Views
Hi there,
i have a simple question:
Is it possible to typecast within a subroutie during runtime like in .NET you can give an object as an income parameter and typecast to whatever explicit type you want (integer, string, and so) ?
The reason why i am asking this is simple:
In our software i am using quite a lot of allocatable arrays which i have to "reallocate" to runtime for increasing or decreasing. (static arrays are not an option :) )
Because i have a few char arrays, a few real arrays, integer arrays and some self defined types arrays its really really boring to write the same reallocate logic for each type of array.
What i want to do is keeping only 1 subroutine (having 30 subroutines which all doing the same is...not stylish ;) ) with a"type open" incoming parameter and typecast it within the subroutine to the type i am needing (by giving an enum to know which type i have to cast for example).
Is this possible with F90 and if so...how to make it :) ?
Best Regards
Oliver
0 Kudos
10 Replies
Arjen_Markus
Honored Contributor II
1,926 Views
Well, what you can do is something along these lines:

module reallocate
interface realloc
module procedure realloc_int1d
module procedure realloc_real1d
...
end interface realloc
contains
subroutine realloc_int1d( array, newsize )
integer, dimension(:), allocatable:: array
include "actual_realloc_code.f90"
endsubroutine

subroutine realloc_real1d( array, newsize )
real, dimension(:), allocatable :: array
include "actual_realloc_code.f90"
endsubroutine
...
end module

Via the INCLUDE statement you canrepeat the boilerplate code.
With derived types you can even put the declarations in such an
INCLUDE file, but I do not have the time at the moment to elaborate
on that.

Note that F2003's move_alloc routine makes life very much simpler.
(No more copying needed)

Regards,

Arjen

0 Kudos
ratzeputz
Beginner
1,926 Views
Hi Arjen and thx for your answer.

Well its indeed the way i am actually doing.
I wrote an interface which i call simply with the old array and the incrementation number.

But i do have to write all subroutines for special types and bind them to the interface, which is quite the main "problem" i have.

Not that i am not know what i am doing hehe...but life would be SO much easier by using only 1 simple subroutine for all cases.

move_alloc routine?
never heard about that but sounds interessing....think i cant use it actually if the whole software is written in F90 can i? (fortran compiler 11 by the way)
EDIT:
tried it already...works great but does not expand the array like i want it to do. but got to know that there is a method like that :)
0 Kudos
Les_Neilson
Valued Contributor II
1,926 Views

newsize = oldsize + increment
allocate (temp(newsize), stat=ierr)
if (ierr == 0) then
temp(1:oldsize) = array
call move_alloc(temp, array)
oldsize = newsize
endif


Les
0 Kudos
John4
Valued Contributor I
1,926 Views

If your version of the compiler supports the /assume:realloc_lhs flag, reallocating an array of any type can be done during the assignment, say:

[fortran]implicit none real, allocatable :: a(:) allocate (a(1:0)) !empty array print *, "0 entries:", a a = [a, 1.] !increase size print *, "1 entry:", a a = [a, 2., 3., 4.] !increase size print *, "4 entries:", a a(:) = [1., 2., 3., 5.] !no reallocation print *, "4 entries:", a a = a(:3) !decrease size print *, "3 entries:", a a = a(:0) !make empty print *, "0 entries:", a end [/fortran]

With /assume:realloc_lhs, you'll have to use (:) for the cases when you want to avoid reallocation, as shown in the example.

0 Kudos
ratzeputz
Beginner
1,926 Views
@Les Neilson and John:
Sorry...no offense to you but: did you read my starting post completly?
I do not have a problem with reallocating an array with a bigger size.
I was asking about type casting during runtime.
For better explanation i will give all of you some pseudo code ( i know its not completly correct fortran code..its pseudo)
[fxfortran]!Definition enum type_real = 1 type_int = 2 type_char = 3 type_mytype = 4 end enum function reallocate_typecasted (inputArray,increment, type_enum) result(typecastedArray) !input object :: inputArray integer increment,type_enum !internal object,allocatable :: typecastedArray select case (type_enum) case (type_real) allocate(typecastedArray(size(inputArray + increment))) typecastedArray = TypeCast(real) !this is the main question ! copy old values into new array . . . end select end function !call newArray = reallocate_typecasted(oldArray,1,type_real)[/fxfortran]
I guess this aint possible in fortran isnt it?
Especially cause F90 is not object orientated...for what i read about it.
The reason why i am asking about is, because i learned programing with .NET (VB and C#) and there are so many cool features what i am missing in fortran and which are does need much less of code (writing one subroutine and typecast depending on an enum for example :) )
And why not making programers life easier :) ?...well...if its possible hehe ;)
But if its not possible...ok...i have to and can live with that..
0 Kudos
IanH
Honored Contributor III
1,926 Views
(What you are asking for doesn't have a lot to do with "object oriented code".)

F90's transfer intrinsic can be used to "type cast" the value of a variable of arbitrary type to a value of another type. The programmer needs to ensure that the "another type" (which can be an array) is large enough to accomodate the size in memory of the original variable, or you will not be able to reverse the type cast. Typically a 1D array of integers is used (perhaps an 1D array of INTEGER(1) under ifort) - so your typecastedArray would need to be a 2D array.

Fortran 2003 introduces a number of other possibilities (CLASS(*) may help), but if you have limited yourself to F90 (seriously??? Its pretty hard to justify that sort of restriction today) then obviously you will be missing out F2003's "cool features".

(Note that allocatable arguments, allocatable function results and allocatable derived type components are all not available in F90.)
0 Kudos
John4
Valued Contributor I
1,926 Views

The problem is that you keep mentioning "reallocation", and for that you can rely on reallocating the array during assignment (which I showed in my previous post), which is a Fortran 2003 feature. Because it's part of the language, it works the same regardless of whether you have an array of intrinsic (logical, integer, real, character) or derived type.

Even though you mentioned that you're restricting yourself to F90, it seems to be a relative restriction for you ---since the ALLOCATABLE attribute for function/subroutine arguments is a Fortran 2003 feature.

Other than the TRANSFER intrinsic, there is no typecasting in Fortran. As IanH suggested, you could use CLASS(*) combined with type-guards (yet another Fortran 2003 feature), but besides being more complex than reallocate on assignment, it's not yet supported by Intel Fortran ---i.e., the CLASS(*) feature still doesn't work well with arrays.

The following should, in theory, be close to what you want (although the code doesn't even compile, so it might not be valid):

[fortran]program test implicit none integer, allocatable :: a(:) character(5), allocatable :: b(:) allocate (a(1), b(2)) a = 1 b = 'two' print *, 'a, before:',a call reallocate(a, [2, 2]) print *, 'a, after:',a print *, 'b, before:',b call reallocate(b, [character(5) :: 'three', 'three', 'three']) print *, 'b, after:',b contains subroutine reallocate (array, increment) class(*), allocatable, intent(INOUT) :: array(:) class(*), intent(IN) :: increment(:) integer, allocatable :: auxi(:) character(5), allocatable :: auxc(:) select type (array) type is (integer) select type (increment) type is (integer) call MOVE_ALLOC(array, auxi) allocate (integer :: array(SIZE(auxi) + SIZE(increment))) array(:SIZE(auxi)) = auxi array(SIZE(auxi)+1:) = increment class default stop 'type not supported' end select type is (character(*)) select type (increment) type is (character(*)) call MOVE_ALLOC(array, auxc) allocate (character(5) :: array(SIZE(auxc) + SIZE(increment))) array(:SIZE(auxc)) = auxc array(SIZE(auxc)+1:) = increment class default stop 'type not supported' end select
class default stop 'type not supported' end select end subroutine end program test[/fortran]

0 Kudos
ratzeputz
Beginner
1,926 Views
Thx again for your answers.
Well its not myself who has limited all to F90. The software our company is developing was very far in development, when i entered the position :)...so its limited by my boss of course :)
John your source code example seems pretty much the thing i need....but F2003 :(
What a pitty.
At the end its exactly what i expected...not possible in my case. :(
But lets see the win of our discus...if our company decides to develop in F2003 in the future there will be a way to do this :)
Anyway...thx again for the lively discussion :)
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,926 Views
Look at Arjen's suggestion #1 again. His technique only requires you to add 5 lines of text per new type.
Using the Fortran Preprocessor, you might be able to reduce this to 1 or 2 lines.

Jim Dempsey
0 Kudos
IanH
Honored Contributor III
1,926 Views
Arjen's suggestion in #1 isn't valid Fortran 90 - it has an allocatable dummy argument.
0 Kudos
Reply