|
From: James Van Buskirk on 24 Apr 2008 13:33 "Charles Coldwell" <coldwell(a)gmail.com> wrote in message news:rzpy773o7yc.fsf(a)gmail.com... > Sure. What I wrote is a Fortran function that implements the "sort" > that comes with the C++ standard library. You could argue that > Fortran should supply a sort intrinsic so that the code isn't > duplicated by many implementors, but that's different from generic > programming. In terms of simplicity, if I wrote a module implementing > compare and exchange for integers, the C++ code above in Fortran would > read > use my_module > data(1) = 23 > data(2) = -1 > data(3) = 9999 > data(4) = 0 > data(5) = 4 > call quicksort(5, compare, exchange) What I don't understand is why you're always passing around these compare and exchange procedures. In Fortran, wouldn't it be more normal to do something like: C:\gfortran\clf\qsort>type qsort.i90 recursive subroutine qsort_sub(Qarray) dimension Qarray(0:) real harvest integer pivot integer left integer right if(size(Qarray) < 2) return call random_number(harvest) pivot = min(int(harvest*size(Qarray)),ubound(Qarray,1)) if(pivot > 0) Qarray(0:pivot:pivot) = Qarray(pivot:0:-pivot) left = 1 right = ubound(Qarray,1) do while(left <= right) do if(left > right) exit if(Qarray(0) < Qarray(left)) exit left = left+1 end do do if(left > right) exit if(.NOT.(Qarray(0) < Qarray(right))) exit right = right-1 end do if(left < right) then Qarray(left:right:right-left) = Qarray(right:left:left-right) left = left+1 right = right-1 end if end do if(left > 1) Qarray(0:left-1:left-1) = Qarray(left-1:0:1-left) call qsort(Qarray(0:left-2)) call qsort(Qarray(left:)) end subroutine qsort_sub C:\gfortran\clf\qsort>type qtest.f90 module mytype_define implicit none private public mytype, assignment(=), operator(<) type mytype integer data end type mytype interface assignment(=) module procedure assign end interface assignment(=) interface operator(<) module procedure less_than end interface operator(<) contains elemental subroutine assign(x,y) type(mytype), intent(out) :: x type(mytype), intent(in) :: y x%data = y%data end subroutine assign elemental function less_than(x,y) type(mytype), intent(in) :: x type(mytype), intent(in) :: y logical less_than less_than = x%data < y%data end function less_than end module mytype_define module i4_mod implicit integer(Q) interface qsort module procedure qsort_sub end interface qsort contains include 'qsort.i90' end module i4_mod module r4_mod implicit real(Q) interface qsort module procedure qsort_sub end interface qsort contains include 'qsort.i90' end module r4_mod module mytype_mod use mytype_define implicit type(mytype) (Q) interface qsort module procedure qsort_sub end interface qsort contains include 'qsort.i90' end module mytype_mod module generic_sort use i4_mod, only: qsort use r4_mod, only: qsort use mytype_mod, only: qsort implicit none end module generic_sort program test use generic_sort use mytype_define implicit none integer, allocatable :: i4x(:) real, allocatable :: r4x(:) type(mytype), allocatable :: mtx(:) integer n integer i real harvest call random_seed() n = 10 allocate(i4x(n)) allocate(r4x(n)) allocate(mtx(n)) do i = 1, n call random_number(harvest) i4x(i) = harvest*n**2 call random_number(harvest) r4x(i) = harvest call random_number(harvest) mtx(i) = mytype(harvest*n**2) end do call qsort(i4x) call qsort(r4x) call qsort(mtx) do i = 1, n write(*,*) i, i4x(i), r4x(i), mtx(i) end do end program test C:\gfortran\clf\qsort>c:\gcc_equation\bin\x86_64-pc-mingw32-gfortran qtest.f90 - oqtest C:\gfortran\clf\qsort>qtest C:\gfortran\clf\qsort>ifort qtest.f90 Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1 Build 20061104 Copyright (C) 1985-2006 Intel Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 8.00.40310.39 Copyright (C) Microsoft Corporation. All rights reserved. -out:qtest.exe -subsystem:console qtest.obj C:\gfortran\clf\qsort>qtest 1 5 6.2769456E-03 10 2 14 3.7755325E-02 10 3 26 0.1845653 10 4 31 0.2239807 10 5 33 0.4793749 53 6 35 0.6826791 10 7 48 0.8232406 10 8 62 0.9100211 10 9 77 0.9194745 53 10 97 0.9970329 61 C:\gfortran\clf\qsort>ftn95 qtest.f90 /link [FTN95/Win32 Ver. 5.0.0 Copyright (c) Silverfrost Ltd 1993-2006] PROCESSING MODULE [<MYTYPE_DEFINE> FTN95/Win32 v5.0.0] NO ERRORS [<ASSIGN> FTN95/Win32 v5.0.0] NO ERRORS [<LESS_THAN> FTN95/Win32 v5.0.0] NO ERRORS [<MYTYPE_DEFINE> FTN95/Win32 v5.0.0] PROCESSING MODULE [<I4_MOD> FTN95/Win32 v5.0.0] NO ERRORS [<QSORT_SUB> FTN95/Win32 v5.0.0] NO ERRORS [<I4_MOD> FTN95/Win32 v5.0.0] PROCESSING MODULE [<R4_MOD> FTN95/Win32 v5.0.0] NO ERRORS [<QSORT_SUB> FTN95/Win32 v5.0.0] NO ERRORS [<R4_MOD> FTN95/Win32 v5.0.0] PROCESSING MODULE [<MYTYPE_MOD> FTN95/Win32 v5.0.0] NO ERRORS [<QSORT_SUB> FTN95/Win32 v5.0.0] NO ERRORS [<MYTYPE_MOD> FTN95/Win32 v5.0.0] PROCESSING MODULE [<GENERIC_SORT> FTN95/Win32 v5.0.0] NO ERRORS [<GENERIC_SORT> FTN95/Win32 v5.0.0] 0066) use generic_sort *** Specific procedure QSORT_SUB of type SUBROUTINE is too similar to QSORT_SUB of type SUBROUTINE for overload QSORT in module R4_MOD. The arguments are too similar. 0091) call qsort(mtx) *** No matching specific procedure for generic overloaded name QSORT 2 ERRORS [<TEST> FTN95/Win32 v5.0.0] *** Compilation failed See how much more simple? And works great! -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
From: James Van Buskirk on 24 Apr 2008 18:19 "James Van Buskirk" <not_valid(a)comcast.net> wrote in message news:-_-dnbCWBbjHWY3VnZ2dnUVZ_vGdnZ2d(a)comcast.com... > And works great! Well, I tried one small change: ! public mytype, assignment(=), operator(<) public mytype, operator(<)!, assignment(=) And named the modified file qtest1.f90 . C:\gfortran\clf\qsort>ifort qtest.f90 Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1 Build 20061104 Copyright (C) 1985-2006 Intel Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 8.00.40310.39 Copyright (C) Microsoft Corporation. All rights reserved. -out:qtest.exe -subsystem:console qtest.obj C:\gfortran\clf\qsort>qtest 1 0 2.0906582E-02 13 2 0 8.1042856E-02 13 3 8 8.6839773E-02 15 4 25 0.1941290 15 5 33 0.2825256 15 6 57 0.3655469 13 7 65 0.4545409 36 8 75 0.4681000 36 9 84 0.4968905 33 10 93 0.5864838 33 C:\gfortran\clf\qsort>ifort qtest1.f90 Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1 Build 20061104 Copyright (C) 1985-2006 Intel Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 8.00.40310.39 Copyright (C) Microsoft Corporation. All rights reserved. -out:qtest1.exe -subsystem:console qtest1.obj C:\gfortran\clf\qsort>qtest1 1 14 0.2617609 9 2 28 0.3624567 9 3 31 0.3778799 11 4 34 0.4567579 19 5 64 0.4780824 20 6 73 0.5333692 24 7 79 0.5638247 36 8 89 0.6962512 41 9 98 0.7379416 72 10 98 0.8467951 77 C:\gfortran\clf\qsort>C:\gfortran\win64\bin\x86_64-pc-mingw32-gfortran -v Using built-in specs. Target: x86_64-pc-mingw32 Configured with: .../../trunk/configure --prefix=/home/FX/irun64 --build=i586-pc- mingw32 --target=x86_64-pc-mingw32 --with-gmp=/home/FX/local --enable-languages= c,fortran --disable-werror --disable-nls --enable-threads Thread model: win32 gcc version 4.4.0 20080421 (experimental) [trunk revision 134506] (GCC) C:\gfortran\clf\qsort>C:\gfortran\win64\bin\x86_64-pc-mingw32-gfortran qtest.f90 -oqtest C:\gfortran\clf\qsort>qtest C:\gfortran\clf\qsort>C:\gfortran\win64\bin\x86_64-pc-mingw32-gfortran qtest1.f9 0 -oqtest1 C:\gfortran\clf\qsort>qtest1 1 7 5.35517931E-03 13 2 33 1.61082745E-02 34 3 34 0.10038292 44 4 40 0.20687431 45 5 59 0.21795171 48 6 64 0.32298726 65 7 66 0.36739087 75 8 74 0.38676596 85 9 90 0.56682467 96 10 99 0.67298073 96 C:\gfortran\clf\qsort>C:\gcc_equation\bin\x86_64-pc-mingw32-gfortran -v Built by Equation Solution (http://www.Equation.com). Using built-in specs. Target: x86_64-pc-mingw32 Configured with: .../gcc-4.4-20080418-mingw/configure --host=x86_64-pc-mingw32 -- build=x86_64-unknown-linux-gnu --target=x86_64-pc-mingw32 --prefix=/home/gfortra n/gcc-home/binary/mingw32/native/x86_64/gcc/4.4-20080418 --with-gmp=/home/gfortr an/gcc-home/binary/mingw32/native/x86_64/gmp --with-mpfr=/home/gfortran/gcc-home /binary/mingw32/native/x86_64/mpfr --with-sysroot=/home/gfortran/gcc-home/binary /mingw32/cross/x86_64/gcc/4.4-20080418 --with-gcc --with-gnu-ld --with-gnu-as -- disable-shared --disable-nls --disable-tls --enable-languages=c,fortran --enable -threads=win32 --enable-libgomp --disable-win32-registry Thread model: win32 gcc version 4.4.0 20080418 (experimental) (GCC) C:\gfortran\clf\qsort>C:\gcc_equation\bin\x86_64-pc-mingw32-gfortran qtest.f90 - oqtest C:\gfortran\clf\qsort>qtest C:\gfortran\clf\qsort>C:\gcc_equation\bin\x86_64-pc-mingw32-gfortran qtest1.f90 -oqtest1 C:\gfortran\clf\qsort>qtest1 1 7 5.35517931E-03 13 2 33 1.61082745E-02 34 3 34 0.10038292 44 4 40 0.20687431 45 5 59 0.21795171 48 6 64 0.32298726 65 7 66 0.36739087 75 8 74 0.38676596 85 9 90 0.56682467 96 10 99 0.67298073 96 So we can see that old ifort and the latest versions of gfortran (both styles) can cope if intrinsic rather than defined assignment is used. Kind of strange because gfortran can handle http://home.comcast.net/~kmbtib/Fortran_stuff/elem_assign.f90 but this stuff with array triplets rather than vector subscripts is too much for it. Also one might have thought that ifort would have gotten it fixed after http://groups.google.com/group/comp.lang.fortran/msg/a76a9ebd13bd04ab but even after issue #345003 +590 days I can't state with confidence that it has been fixed. I sure haven't been notified if so. Salford/Silverfrost barfs at the same place in the modified version. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
From: Charles Coldwell on 24 Apr 2008 20:12 "James Van Buskirk" <not_valid(a)comcast.net> writes: > "Charles Coldwell" <coldwell(a)gmail.com> wrote in message > news:rzpy773o7yc.fsf(a)gmail.com... > >> Sure. What I wrote is a Fortran function that implements the "sort" >> that comes with the C++ standard library. You could argue that >> Fortran should supply a sort intrinsic so that the code isn't >> duplicated by many implementors, but that's different from generic >> programming. In terms of simplicity, if I wrote a module implementing >> compare and exchange for integers, the C++ code above in Fortran would >> read > >> use my_module >> data(1) = 23 >> data(2) = -1 >> data(3) = 9999 >> data(4) = 0 >> data(5) = 4 >> call quicksort(5, compare, exchange) > > > What I don't understand is why you're always passing around these > compare and exchange procedures. In Fortran, wouldn't it be more > normal to do something like: [ snip ] > module i4_mod > implicit integer(Q) > interface qsort > module procedure qsort_sub > end interface qsort > contains > include 'qsort.i90' > end module i4_mod > > module r4_mod > implicit real(Q) > interface qsort > module procedure qsort_sub > end interface qsort > contains > include 'qsort.i90' > end module r4_mod > > module mytype_mod > use mytype_define > implicit type(mytype) (Q) > interface qsort > module procedure qsort_sub > end interface qsort > contains > include 'qsort.i90' > end module mytype_mod Well, if you don't object to implicit typing, it's a pretty clever solution, although the "includes" sort of imply a certain amount of code duplication, although I guess I wouldn't really call it that. What you are doing here is very close to what would be called "template instantiation" in C++, and like template instantiation, your includes are evaluated at compile time. > 0091) call qsort(mtx) > *** No matching specific procedure for generic overloaded name QSORT > 2 ERRORS [<TEST> FTN95/Win32 v5.0.0] > *** Compilation failed Heh. You are exploring the dusty corners of the F95 spec. It may be conforming code, but you have confused at least one compiler. > See how much more simple? And works great! Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out" GPG Key ID: 852E052F GPG Key Fingerprint: 77E5 2B51 4907 F08A 7E92 DE80 AFA9 9A8F 852E 052F
From: Jim Xia on 7 May 2008 00:42 On May 2, 5:33 pm, "James Van Buskirk" <not_va...(a)comcast.net> wrote: > "Jim Xia" <jim...(a)hotmail.com> wrote in message > > news:c81e0a74-b847-4aa7-8dc9-4012774b277f(a)m73g2000hsh.googlegroups.com... > > > Resistance to templates in Fortran is likely by the standard body > > since it'll hurt performance due to code-bloat. Fortran is known to > > generate fast code that C++ can even dream of. Any feature > > endangering that capability is not going to be an easy sell. That > > also explains why coarrays are welcomed to the language while the > > templates are still being talked about. > > Fortran has language features that C++ doesn't have that make > templates more awkward. One of my favorites is that of having 3 > different classes of expressions: ordinary expressions, > initialization expressions, and specification expressions. > Consider the following example, where template code is used for > 9 different instances: all 3 real KINDs times 3 different functions. > Since in f03 pretty much any intrinsic elemental function may take > part in an initialization epression, in our template code we must > be ready to handle named constants whose type is unknown to us as > we write the template code. I don't see how to handle this in > the general case, but if the type is constrained to be numeric it > can be done! Consider the following example: > > C:\gfortran\test\num_init>type finit.s > .text > .globl _xfinit_ > .def _xfinit_; .scl 2; .type 32; .endef > _xfinit_: > finit > ret > > C:\gfortran\test\num_init>type num_init.i90 > subroutine initr1_template(Q) > parameter(Qarg1 = x) > integer, parameter :: k2 = kind(fun(Qarg1)) > integer, parameter :: is_int = 1-1/(2+0*fun(Qarg1))*2 > integer, parameter :: kind_if_real = & > (1-is_int)*k2+is_int*kind(1.0) > integer, parameter :: is_cmplx = -((1-is_int)* & > transfer(cmplx(0,1,kind_if_real),fun(Qarg1)))**2 > integer, parameter :: is_real = 1-is_int-is_cmplx > integer, parameter :: kind_if_int = is_int*k2+(1-is_int)*kind(1) > integer(kind_if_int), parameter :: iparam = is_int*fun(Qarg1) > real(kind_if_real), parameter :: rparam = is_real*fun(Qarg1) > complex(kind_if_real), parameter :: cparam = is_cmplx*fun(Qarg1) > character(7), parameter :: type_label_array(3) = & > ['INTEGER','REAL ','COMPLEX'] > character(*), parameter :: type_label = & > trim(type_label_array(is_int+2*is_real+3*is_cmplx)) > character(100) fmt > integer s > > write(*,'(a)') 'Test of '//name//' intrinsic' > write(*,'(a,i0)') 'k2 = ', k2 > write(*,'(a,i0)') 'is_int = ', is_int > write(*,'(a,i0)') 'kind_if_real = ', kind_if_real > write(*,'(a,i0)') 'is_cmplx = ', is_cmplx > write(*,'(a,i0)') 'is_real = ', is_real > write(*,'(a,i0)') 'kind_if_int = ', kind_if_int > write(*,'(2a)') 'type_label = ', type_label > if(is_int == 1) then > write(*,'(a,i0)') name//'('//arg1//') = ', iparam > else if(is_real == 1) then > s = precision(rparam) > write(fmt,'(3(a,i0))') '(a,g',s+9,'.',s+2,')' > write(*,fmt) name//'('//arg1//') = ', rparam > else if(is_cmplx == 1) then > s = precision(cparam) > write(fmt,'(3(a,i0))') '(3(a,g',s+9,'.',s+2,'))' > write(*,fmt) name//'('//arg1//') = (', & > real(cparam), ',', aimag(cparam), ')' > end if > end subroutine initr1_template > > C:\gfortran\test\num_init>type initr1.f90 > module mykinds > implicit none > integer, parameter :: ck1 = kind('x') > integer, parameter :: ik1 = selected_int_kind(2) > integer, parameter :: ik2 = selected_int_kind(4) > integer, parameter :: ik4 = selected_int_kind(9) > integer, parameter :: ik8 = selected_int_kind(18) > integer, parameter :: Lk1 = ik1 > integer, parameter :: Lk2 = ik2 > integer, parameter :: Lk4 = ik4 > integer, parameter :: Lk8 = ik8 > integer, parameter :: sp = selected_real_kind(6,37) > integer, parameter :: dp = selected_real_kind(15,307) > integer, parameter :: ep = selected_real_kind(18,4931) > integer, parameter :: qp_preferred = selected_real_kind(33,4931) > integer, parameter :: qp = (1+sign(1,qp_preferred))/2*qp_preferred+ & > (1-sign(1,qp_preferred))/2*ep > type mytype > integer(ik4) data > end type mytype > end module mykinds > > module name_mod > use mykinds, only: qp > private qp > intrinsic INT > intrinsic ABS > intrinsic CMPLX > !DEC$ IF DEFINED(.FALSE.) > intrinsic BESSEL_J0 > !DEC$ ENDIF > intrinsic ERF > intrinsic SPACING > character(*), parameter :: int_name = 'INT' > character(*), parameter :: int_arg1 = 'X' > real(qp), parameter :: int_X = 1.795195802051310421978653361874_qp > character(*), parameter :: abs_name = 'ABS' > character(*), parameter :: abs_arg1 = 'X' > real(qp), parameter :: abs_X = 1.795195802051310421978653361874_qp > character(*), parameter :: cmplx_name = 'CMPLX' > character(*), parameter :: cmplx_arg1 = 'X' > real(qp), parameter :: cmplx_X = 1.795195802051310421978653361874_qp > end module name_mod > > module int_mod > use name_mod, only: fun=> INT > use name_mod, only: name => int_name > use name_mod, only: arg1 => int_arg1 > use name_mod, only: X => int_X > end module int_mod > > module abs_mod > use name_mod, only: fun=> ABS > use name_mod, only: name => abs_name > use name_mod, only: arg1 => abs_arg1 > use name_mod, only: X => abs_X > end module abs_mod > > module cmplx_mod > use name_mod, only: fun=> CMPLX > use name_mod, only: name => cmplx_name > use name_mod, only: arg1 => cmplx_arg1 > use name_mod, only: X => cmplx_X > end module cmplx_mod > > module initr1_sp_int > use mykinds > use int_mod > implicit real(sp) (Q) > private > public initr1_int > interface initr1_int > module procedure initr1_template > end interface initr1_int > contains > include 'num_init.i90' > end module initr1_sp_int > > module initr1_dp_int > use mykinds > use int_mod > implicit real(dp) (Q) > private > public initr1_int > interface initr1_int > module procedure initr1_template > end interface initr1_int > contains > include 'num_init.i90' > end module initr1_dp_int > > module initr1_qp_int > use mykinds > use int_mod > implicit real(qp) (Q) > private > public initr1_int > interface initr1_int > module procedure initr1_template > end interface initr1_int > contains > include 'num_init.i90' > end module initr1_qp_int > > module initr1_sp_abs > use mykinds > use abs_mod > implicit real(sp) (Q) > private > public initr1_abs > interface initr1_abs > module procedure initr1_template > end interface initr1_abs > contains > include 'num_init.i90' > end module initr1_sp_abs > > module initr1_dp_abs > use mykinds > use abs_mod > implicit real(dp) (Q) > private > public initr1_abs > interface initr1_abs > module procedure initr1_template > end interface initr1_abs > contains > include 'num_init.i90' > end module initr1_dp_abs > > module initr1_qp_abs > use mykinds > use abs_mod > implicit real(qp) (Q) > private > public initr1_abs > interface initr1_abs > module procedure initr1_template > end interface initr1_abs > contains > include 'num_init.i90' > end module initr1_qp_abs > > module initr1_sp_cmplx > use mykinds > use cmplx_mod > implicit real(sp) (Q) > private > public initr1_cmplx > interface initr1_cmplx > module procedure initr1_template > end interface initr1_cmplx > contains > include 'num_init.i90' > end module initr1_sp_cmplx > > module initr1_dp_cmplx > use mykinds > use cmplx_mod > implicit real(dp) (Q) > private > public initr1_cmplx > interface initr1_cmplx > module procedure initr1_template > end interface initr1_cmplx > contains > include 'num_init.i90' > end module initr1_dp_cmplx > > module initr1_qp_cmplx > use mykinds > use cmplx_mod > implicit real(qp) (Q) > private > public initr1_cmplx > interface initr1_cmplx > module procedure initr1_template > end interface initr1_cmplx > contains > include 'num_init.i90' > end module initr1_qp_cmplx > > module initr1_mod > use initr1_sp_int > use initr1_dp_int > use initr1_qp_int > use initr1_sp_abs > use initr1_dp_abs > use initr1_qp_abs > use initr1_sp_cmplx > use initr1_dp_cmplx > use initr1_qp_cmplx > end module initr1_mod > > program initr1_test > use mykinds > use initr1_mod > use name_mod > implicit none > real(sp) xr > real(dp) xd > real(qp) xq > > !DEC$ IF DEFINED(.FALSE.) > call xfinit ! Workaround for gfortran bug > !DEC$ ENDIF > xr = int_X > xd = int_X > xq = int_X > call initr1_int(xr) > call initr1_int(xd) > call initr1_int(xq) > xr = abs_X > xd = abs_X > xq = abs_X > call initr1_abs(xr) > call initr1_abs(xd) > call initr1_abs(xq) > xr = cmplx_X > xd = cmplx_X > xq = cmplx_X > call initr1_cmplx(xr) > call initr1_cmplx(xd) > call initr1_cmplx(xq) > end program initr1_test > > C:\gfortran\test\num_init>gfortran initr1.f90 finit.s -oinitr1 > > C:\gfortran\test\num_init>initr1 > Test of INT intrinsic > k2 = 4 > is_int = 1 > kind_if_real = 4 > is_cmplx = 0 > is_real = 0 > kind_if_int = 4 > type_label = INTEGER > INT(X) = 1 > Test of INT intrinsic > k2 = 4 > is_int = 1 > kind_if_real = 4 > is_cmplx = 0 > is_real = 0 > kind_if_int = 4 > type_label = INTEGER > INT(X) = 1 > Test of INT intrinsic > k2 = 4 > is_int = 1 > kind_if_real = 4 > is_cmplx = 0 > is_real = 0 > kind_if_int = 4 > type_label = INTEGER > INT(X) = 1 > Test of ABS intrinsic > k2 = 4 > is_int = 0 > kind_if_real = 4 > is_cmplx = 0 > is_real = 1 > kind_if_int = 4 > type_label = REAL > ABS(X) = 1.7951958 > Test of ABS intrinsic > k2 = 8 > is_int = 0 > kind_if_real = 8 > is_cmplx = 0 > is_real = 1 > kind_if_int = 4 > type_label = REAL > ABS(X) = 1.7951958020513104 > Test of ABS intrinsic > k2 = 10 > is_int = 0 > kind_if_real = 10 > is_cmplx = 0 > is_real = 1 > kind_if_int = 4 > type_label = REAL > ABS(X) = 1.7951958020513104220 > Test of CMPLX intrinsic > k2 = 4 > is_int = 0 > kind_if_real = 4 > is_cmplx = 1 > is_real = 0 > kind_if_int = 4 > type_label = COMPLEX > CMPLX(X) = ( 1.7951958 , 0.0000000 ) > Test of CMPLX intrinsic > k2 = 4 > is_int = 0 > kind_if_real = 4 > is_cmplx = 1 > is_real = 0 > kind_if_int = 4 > type_label = COMPLEX > CMPLX(X) = ( 1.7951958 , 0.0000000 ) > Test of CMPLX intrinsic > k2 = 4 > is_int = 0 > kind_if_real = 4 > is_cmplx = 1 > is_real = 0 > kind_if_int = 4 > type_label = COMPLEX > CMPLX(X) = ( > > read more »... Thanks for your reply. C++ also has many features that Fortran is lacking. The dynamic initializations, for example, are also awkward to simulate in Fortran if you ever want to try. I don't think initialization expressions and specification expressions are big issues here since C/C++ is using them as well -- they're not unique to Fortran. What unique to Fortran is the extent for these expressions using intrinsic functions. C supports automatic variables that uses specification expressions, and any constants you declare in C must be defined using init-expr, and all static variables in C must also be initialized with init-expr. Compiler does all the tricks to get all the expressions (either init-expr or spec-expr) evaluated at the right time. I don't see how this can not be done too for templates. What I'm interested at the moment is the function templates in Fortran. By borrowing some of the C++ syntax, I hope I can explain what I have in mind clearly. Say you want to define a generic subroutine swap between two objects a and b, you can consider an interface similar to the following: template <S, T> subroutine swap (a, b) type(S) a type(T) b !... real :: local_array(a%kind * b%kind) !<-- should have no problem for this declaration !... end subroutine Both type S and T and their type parameters can be determined at the call statement, such as call swap (i, r) If this subroutine is defined in a module, then I don't see much of a technical issue for compiler to implement this. Again I maintain that only when there are enough demands. In addition to above function templates, there is also a need for template to complement the derived type with type parameters. Currently the way F03 defines for kind type parameters for derived types renders very little use for it by the type bound procedures. It is really awful to make a use of such a type. Consider the following type type counter (k) integer, kind :: k integer(k) :: count contains procedure :: increment end type ... Since the kind type parameters must be init-expr, there is no easy way to define a generic type bound subroutine increment for all kind values. So if type parameter k can be 1, 2, 4 and 8, then you must define 4 different increment routines to implement the same logic. Here again the template is needed: template <k> subroutine increment (c) class(counter(k)), intent(inout) :: c c%count = c%count + 1 end subroutine ... The you can understand what I meant for the following code type(counter(8)) c ... call c%increment !<-- we know c%k is 8 at invocation ... Hope this explains :-) Cheers,
From: Bálint Aradi on 7 May 2008 04:36
Tobias, Jim, On Apr 30, 5:07 pm, Jim Xia <jim...(a)hotmail.com> wrote: > The correct syntax for your code should be something like this > > module sort > type, abstract :: sortType > integer :: n > contains > procedure(comp_func), deferred, pass(this) :: compare > procedure(exch_func), deferred, pass(this) :: exchange > end type > > abstract interface > integer function comp_func(i,j, this) > import > integer :: i, j > class(sorttype) :: this > end function comp_func > > subroutine exch_func(i,j, this) > import > integer :: i, j > class(sorttype) :: this > end subroutine exch_func > end interface > contains > subroutine quicksort(data) > class(sortType) :: data > ! ... > if (data%compare(i,j) > 0) call data%exchange(i,j) > ! ... > end subroutine quicksort > end module sort > > module myDataType > use sort > type, extends(sortType) :: myType > private > integer, allocatable :: i(:) > contains > procedure, pass(this) ::set > procedure, pass(this) ::compare > procedure, pass(this) ::exchange > end type > > contains > subroutine set(array, this) > integer :: array(:) > class(myType) :: this > this%i = data > this%n = size(array) > end subroutine set > subroutine exchange(i, j, this) > integer :: i, j > class(myType) :: this > integer :: tmp > tmp = this%i(i) > this%i(i) = this%i(j) > this%i(j) = tmp > end subroutine exchange > integer function compare(i,j, this) > integer :: i, j > class(myType) :: this > ! ... > end function compare > ! ... > end module myDataType The problem with your solution is that it uses inheritance. As F03 only enables single inheritance and the language does not offer any alternative options (e.g. as interfaces in Java), your type to be sorted must be a child of sortType. However, what happens if myDataType is a pretty complex type, and was created by extending a type called myDataParent? And let's assume, myDataParent is defined somewhere else in the code, and you are not allowed/able to change its definition. Then, you don't have the possibility to make it a child of sortType, and therefore it can't be sorted, There are many realistic example, where in scientific code multiple inheritance (or Java-like interfaces) would be required. For the case above templates could be alternative solution, but if you already know at compile time, what do you want to sort. However, if that depends on some external parameters (user input), it won't work either. Bálint |