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

Need help about the overriding operator in extened type and report a strange issue

Li_L_
New Contributor I
290 Views
module vector_
implicit none

    private
    public:: vector
    
    integer,parameter:: rp=8,ip=4
!types
!-----------------------
    type::  vector
        private
        real(rp),allocatable,dimension(:):: vc
    contains
        generic::           init    => init_vector
        procedure,private:: init_vector
        
        generic::           operator(*) => vsMultiply,svMultiply
        procedure,pass(lhs),private::  vsMultiply
        procedure,pass(rhs),private::  svMultiply
    end type vector
!-----
contains
    
    !&&
    pure subroutine init_vector(this,v)
    class(vector),intent(out)::                 this
    class(vector),intent(in)::                  v
        allocate( this%vc( size(v%vc) ) )
        this%vc = v%vc
    end subroutine init_vector
    
    elemental function svMultiply(lhs,rhs) result(vr)
    real(rp),intent(in)::               lhs
    class(vector),intent(in)::          rhs
    type(vector)::                      vr
        allocate( vr%vc( size(rhs%vc) ) )
        vr%vc = lhs * rhs%vc
    end function svMultiply
    !--
    elemental function vsMultiply(lhs,rhs) result(vr)
    class(vector),intent(in)::          lhs
    real(rp),intent(in)::               rhs
    type(vector)::                      vr
        call vr%init( rhs * lhs )
    end function vsMultiply
    !--

end module vector_

module polynomial_
use vector_
implicit none

    private
    public:: polynomial
    
    integer,parameter:: rp=8,ip=4
    !-----------------------------------------
    type,extends(vector):: polynomial
    contains
        !the below p1=> error #5286: Ambiguous generic interface OPERATOR(*): previously declared specific procedure VECTOR_::SVMULTIPLY is not distinguishable from this declaration. [SPMULTIPLY]
        generic::           operator(*) =>  spmultiply
        procedure,pass(rhs),private::   spMultiply
        !the below p2=>error #8280: An overriding binding and its corresponding overridden binding must both be either subroutines or functions with the same result type, kind, and shape.   [SVMULTIPLY]
        !procedure,pass(rhs),private::   svMultiply => spMultiply

    end type polynomial
!-----------------------------------------
contains
    !--
    elemental function spMultiply(lhs,rhs) result(p)
    real(rp),intent(in)::               lhs
    class(polynomial),intent(in)::      rhs
    type(polynomial)::                  p
        call p%init(rhs)
    end function spMultiply
    
end module polynomial_

program test
use vector_
use polynomial_
implicit none

    print*, 'ok'

end program test

here I meet some problems.

I have two types: one is <vector>, and another one is <polynomial> which is the subclass of <vector>

I want to override the operator(*) of <vector> in <polynomial> which makes the result follow the type of input

Method1: I tried to add <spMultiply> into the generic binding procedure, it leads problem1

Method2: I tried to override the <svMultiply>, it leads problem2

So is there anyone can help me solve this overriding procedure and realize my thought. I ever tried to change the class of output in <svMultiply> to <class(vector),allocatable::>, but <elemental> attribution refuse the declaration of <allocatable> for function output.

 

!!!the real problem!!!

Actually another worse problem is that I successfully override the operator<*> by method1 in a big code. Then a type(polynomial) can produce a type(polynomial) when multiplying REAL. But I can’t reproduce this successful compilation in this simplified version.

the f90 attached is a version can override operator<*>. it can run directly. 

i  want to know whether method1 is an legal overriding procedure for operator?

i use the VS2013+intelfortran2017

0 Kudos
8 Replies
Li_L_
New Contributor I
290 Views

 i find the reason which leads to this strange compiling behavior

 

once the operator(*) of <vector> is not the first overriden generic operator, method1 can be passed through the compiler check

like:

generic:: operator(+)=> <someproc> 

added in line 16

but this compiling will still fails if the other overriden operator added behind the operator(*)

 

for now, i still want an legal and robust way to override the operator which can produce the different type output

<class,allocatable> is not a preferred way because <elemental> attribution is quite convenient for coding

0 Kudos
FortranFan
Honored Contributor II
290 Views

Li L. wrote:

.. for now, i still want an legal and robust way to override the operator which can produce the different type output ..

@Li L,

What are all your use cases with the extended operator(*) in the child derived type?  Note for situations that are like or similar to this:

    z = x * y

where z is the child type and either x or y is the child type while the other is a real scalar of kind rp, all you would need is to introduce a defined assignment in the child type which has a second dummy argument of the parent type.

 

0 Kudos
Li_L_
New Contributor I
290 Views
FortranFan wrote:

Quote:

Li L. wrote:

.. for now, i still want an legal and robust way to override the operator which can produce the different type output ..

@Li L,

What are all your use cases with the extended operator(*) in the child derived type?  Note for situations that are like or similar to this:

    z = x * y

where z is the child type and either x or y is the child type while the other is a real scalar of kind rp, all you would need is to introduce a defined assignment in the child type which has a second dummy argument of the parent type.

 

for example p1 = r * p2 *p3 if i don't override operator of polynomial r*p2=vector, rather than polynomial vector*p3 is wrong and nonsense as you say, a split step seems work. but it definitely confusing me in the future when i check the code with the literature. a compact expression, totally the same as the paper can help me work better
0 Kudos
FortranFan
Honored Contributor II
290 Views

Li L. wrote:

.. for example

p1 = r * p2 *p3
if i don't override operator of polynomial
r*p2=vector, rather than polynomial
vector*p3 is wrong and nonsense

.. when i check the code with the literature. a compact expression, totally the same as the paper can help me work better

Why is it nonsense?  Based on what you show, a polynomial is effectively the same as vector; in fact, one can ask why even extend vector to make it a polynomial!

Also, what literature are you referring to?  Which paper, and what is the "compact expression"?  Does it have a design pattern in some other language you're trying to mimic with Fortran?

0 Kudos
FortranFan
Honored Contributor II
290 Views

Li L. wrote:

..

for example

p1 = r * p2 *p3

..

Keep in mind you don't need necessarily work with type-bound generic operators; in fact, case can be made that abstraction for multiplications, etc. be achieved via module procedures rather than TBPs - many will find them clearer to understand and easier to implement, as aspect in which you express an interest.  Moreover there may be some performance benefit given the fact the code can then work with explicit derived types rather than the polymorphic instances.

0 Kudos
Li_L_
New Contributor I
290 Views

FortranFan wrote:

Quote:

Li L. wrote:

 

..

for example

p1 = r * p2 *p3

..

 

 

Keep in mind you don't need necessarily work with type-bound generic operators; in fact, case can be made that abstraction for multiplications, etc. be achieved via module procedures rather than TBPs - many will find them clearer to understand and easier to implement, as aspect in which you express an interest.  Moreover there may be some performance benefit given the fact the code can then work with explicit derived types rather than the polymorphic instances.

module procedures is a good choice

explicit derived type increase the code lines. but if you are definitely sure about the benefit of performance, no matter how much, i will try

 

anymore, can you reproduce the strange compiling. that method1: i can override the second or later generic operator by adding function in generic binding, but compiling fails when doing that for the first generic operator.

is that a compiler debug? this generic binding add is permitted or not?

0 Kudos
FortranFan
Honored Contributor II
290 Views

Li L. wrote:

.. p1 = r * p1 * p2 ..

Upon further thought, you don't really need to override the scalar * vector and the vector * scalar operator in the polynomial type.  You should be able to work by simply extending the generic operator(*) with 2 more procedures, a) with your ppMultiply where lhs -> class(polynomial) and rhs -> type(polynomial) and b) with, say, a vpMultiply where lhs -> type(vector) and rhs -> class(polynomial).

But you can also try the module procedure option and do performance comparisons.

0 Kudos
Li_L_
New Contributor I
290 Views

FortranFan wrote:

Quote:

Li L. wrote:

 

.. p1 = r * p1 * p2 ..

 

 

Upon further thought, you don't really need to override the scalar * vector and the vector * scalar operator in the polynomial type.  You should be able to work by simply extending the generic operator(*) with 2 more procedures, a) with your ppMultiply where lhs -> class(polynomial) and rhs -> type(polynomial) and b) with, say, a vpMultiply where lhs -> type(vector) and rhs -> class(polynomial).

But you can also try the module procedure option and do performance comparisons.

permitting the vector*polynomial is a dangerous logic for the program, as i think.

like if you considering the superclass as <2 dimensional vector>, and subclass as <3 dimensional vector>, which is a very nature inheritance

and in superclass we define real*2dvector = 2dvector

due to the lack of an effective overriding method

we have to admit the existence of real*3dvector = 2dvector, and then for correcting this logic, define an operation of <2dvector .op. 3dvector>

in mathematics, this operator definition breaks the completeness of 3d space. in code, this expression losses <z> 

<class(2dvector),allocatable> as the output may help, but <elemental> is also a fundamental attribution for operator procedure

 

after a long time for considering this questions, i think a module interface is a safer way to override the intrinsic operator.

type binding operator is not suitable for extended type

0 Kudos
Reply