|
From: Richard Maine on 7 May 2008 10:33 B�lint Aradi <aradi(a)bccms.uni-bremen.de> wrote: > 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, You can, however, make a type myDataSortType, which extends sortType and has a component of type myDataType. If I have my terminology straight, this would be using imbedding. While one might argue that this introduces a slight extra complication, it is *HUGELY* simpler than the complications of multiple inheritance. The omission of multiple inheritance was considered and deliberate. > There are many realistic example, where in scientific code multiple > inheritance (or Java-like interfaces) would be required. I disagree, unless one has a strange definition of "required". Substitute "could be used" instead of "required" and the statement is more defensible, but then one needs to evaluate the cost-benefit tradeoffs. The costs of multiple inheritance would have been huge. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
From: James Van Buskirk on 7 May 2008 10:54 "B�lint Aradi" <aradi(a)bccms.uni-bremen.de> wrote in message news:5ce6b402-656e-4215-8107-02b597b4f5bd(a)d77g2000hsb.googlegroups.com... > 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. You can decide at run time how you want to sort by redefining your comparison operator: C:\gfortran\test\cray_overload>type cray_overload.f90 module mytype_mod implicit none type mytype integer ikey real rkey end type mytype interface operator(<) pure function less_than(x,y) import mytype type(mytype), intent(in) :: x type(mytype), intent(in) :: y logical less_than end function less_than end interface operator(<) pointer (p_lt, less_than) contains pure function compare_int(x,y) type(mytype), intent(in) :: x type(mytype), intent(in) :: y logical compare_int compare_int = x%ikey < y%ikey end function compare_int pure function compare_real(x,y) type(mytype), intent(in) :: x type(mytype), intent(in) :: y logical compare_real compare_real = x%rkey < y%rkey end function compare_real end module mytype_mod program test use mytype_mod implicit none type(mytype) A type(mytype) B A = mytype(3, 7.0) B = mytype(5, 2.0) p_lt = loc(compare_int) call sub(A,B) p_lt = loc(compare_real) call sub(A,B) end program test subroutine sub(A, B) use mytype_mod, only: mytype, operator(<) implicit none type(mytype) A type(mytype) B write(*,*) 'A = ', A write(*,*) 'B = ', B write(*,*) 'A < B = ', A < B end subroutine sub C:\gfortran\test\cray_overload>gfortran -fcray-pointer cray_overload.f90 -ocray_ overload C:\gfortran\test\cray_overload>cray_overload A = 3 7.0000000 B = 5 2.0000000 A < B = T A = 3 7.0000000 B = 5 2.0000000 A < B = F C:\gfortran\test\cray_overload>ifort cray_overload.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:cray_overload.exe -subsystem:console cray_overload.obj C:\gfortran\test\cray_overload>cray_overload A = 3 7.000000 B = 5 2.000000 A < B = T A = 3 7.000000 B = 5 2.000000 A < B = F The above example uses cray pointers to achieve the operator redefinition, but when f03 procedure pointers get implemented it should be possible to produce a more portable version of my example. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
From: Jim Xia on 7 May 2008 11:21 Just repost what I said ... > > 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: 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: Jim Xia on 7 May 2008 11:35
> You can, however, make a type myDataSortType, which extends sortType and > has a component of type myDataType. If I have my terminology straight, > this would be using imbedding. This is called containment in OOP design. > The omission of multiple inheritance was considered and deliberate. I'm glad Fortran has chosen single inheritance. I think you can resolve most issues, if not all of them, for the need of Java-like interfaces by using containment relationship. Inheritance is not the only way to solve the generic algorithm issues. Cheers, Jim |