Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Same Type As Requirement #19

Open
everythingfunctional opened this issue Oct 22, 2020 · 5 comments
Open

Same Type As Requirement #19

everythingfunctional opened this issue Oct 22, 2020 · 5 comments

Comments

@everythingfunctional
Copy link
Member

One thing that seems to come up frequently in generics (especially with what seems to be the quintessential example for Fortran), is specifying a "Trait" (or a "template" procedure) in such a way as two (or more) arguments must have the same type. For example, if I want to define a trait that requires the add function, in (psuedo)code, I'd like to have it look something like the following:

trait addable
  function add(x, y) result(z)
    type(addable), intent(in) :: x
    type(typeof(x)), intent(in) :: y
    type(typeof(x)) :: z
  end function
end trait

but (AFAIK), typeof only works for variables with a declared, specific type. I think it would make sense to have it work in this context, but it's something we should be thinking about.

@tclune
Copy link
Member

tclune commented Oct 23, 2020

@everythingfunctional I don't think you need to be so pessimistic on this front. The requirement your are describing is an important one even without traits.

Use cases will matter though. For instance what is it about x, y and z being the same type that is important here? To examine this we need some additional pseudo syntax to relate the trait back to the actual template. (First I had to go find a more complicated Rust example to see what happens when the trait involved additional types.) Consider the following as a generalization of what I understand from your example

trait addable<Tx,Ty, Tz>   ! Encapsulate the aspect that Tx's and Ty's can be added to produce Tz's
  function add(x, y) result(z)
    type(Tx), intent(in) :: x
    type(Ty), intent(in) :: y
    type(Tz) :: z
  end function
end trait

template  subroutine  s<Tx,Ty,Tz>(x)
    trait(addable) :: Tx
    type(Tx), intent(in) :: x

    type(Ty) :: tmp_y
    type(Tz) :: tmp_z
    ...
end subroutine

The case where all 3 type parameters are the same type is then just a special case. But the new template will support

  • int + int
  • int + real
  • int + complex
  • real + complex
    and with the order swapped and with all variant kinds.

One of the abstract lessons I have learned with Magne is that one should not be stingy with type parameters. When you think two types "must" be the same, it is really just a relation between them that is screaming to get out. (E.g., the ability to add in this case.) I envision TYPEOF and CLASSOF will become relatively rare in advanced templates. But still absolutely necessary on occasion.

PS the new TYPEOF does not require the additional TYPE. In your example above, z would be declared as TYPEOF(x) :: z

@tclune
Copy link
Member

tclune commented Oct 23, 2020

This is a bit tangential, but I thought some more about this issue. In the add example, there are two possibilities. The first is that this is a type-bound procedure. The second is that this is a regular procedure. Unfortunately with Fortran, both cases have the same interface and the difference is in how the interface is accessed. So is the specified trait a promise that the type has a type-bound procedure named "add" , or that there is a publicly accessible procedure of that name

Unfortunately, I think we really need to support both cases, and therefore will need to invent some sort of notation to make the distinction.

@mleair
Copy link

mleair commented Oct 23, 2020

Having special trait syntax to ensure that two or more dummy arguments are the same type seems a bit overkill. I would think that declaring the dummy arguments (and/or function result) with the same template type parameter will be a more common use case (and it will ensure that the two objects are the same type).

For example,

function add < T > (x, y) result(z)
type(T), intent(in) :: x
type(T), intent(in) :: y
type(T) :: z
end function

But there might be a legitimate concern on T being a valid type for add(). And what constitutes a valid type could be spelled out in a "trait" syntax.

Edit: Had to add some space to < T > to get it to show up in the saved message.

@wclodius2
Copy link
Contributor

I thought the idea was to avoid discussing syntax at this stage. In any case it is ambiguous where you want to define the "trait", in the generic or in the context of instantiation. I can see two ways of defining the "trait" in the generic. In Fortranesque pseudocode as a type attribute

module uses_add( T )
    type :: T
    contains
        procedure(adder) :: add
    end type T
    abstract interface
        function adder(x, y) result(z)
            type(T), intent(in) :: x, y
            type(T) :: z
        end function adder
    end interface
    ...
end module uses_add

or as a separate procendure

module uses_add( T, add )
    type :: T
    end type T
    abstract interface
        function add(x, y) result(z)
            type(T), intent(in) :: x, y
            type(T) :: z
        end function add
    end interface
    ...
end module uses_add

If you really want to use typeof

module uses_add( T )
    type :: T
    contains
        procedure(adder) :: add
    end type T
    abstract interface
        function adder(x, y) result(z)
            type(T), intent(in) :: x
            typeof(x), intent(in) :: y
            typeof(x) :: z
        end function adder
    end interface
    ...
end module uses_add

@tclune
Copy link
Member

tclune commented Oct 24, 2020

@wclodius2 Yes - the approach you suggest is pretty much what Magne and I had been considering in our discussions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants