From: James Van Buskirk on
"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
"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
"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
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
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