# Examples for the new @ rank agnostic array notation

**URL:** <https://fortran-lang.discourse.group/t/examples-for-the-new-rank-agnostic-array-notation/1376>\
**Category:** Uncategorized\
**Created:** [June 10, 2021, 7:56pm UTC](https://fortran-lang.discourse.group/t/examples-for-the-new-rank-agnostic-array-notation/1376 "2021-06-10T19:56:08Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [June 10, 2021, 7:56pm UTC](https://fortran-lang.discourse.group/t/examples-for-the-new-rank-agnostic-array-notation/1376/1 "2021-06-10T19:56:08Z")

</div>

At one of the last J3 meetings, the following feature has passed:

[Rank-agnostic array element and section denotation · Issue #157 · j3-fortran/fortran\_proposals · GitHub](https://github.com/j3-fortran/fortran_proposals/issues/157)

The issue has some examples. What other examples would you use this in? I would like to see several diverse examples so that we can write a tutorial on this feature, as well as see if we need to submit some proposals to make this feature more useful.

For example, right now it would allow to write code like this (see the issue for context):

```auto
subroutine max_at(x, q1, q2, q3, vec)
real, intent(in) :: x(..)
real, intent(in) :: q1(..)
real, intent(in) :: q2(..)
real, intent(in) :: q3(..)
real, intent(out) :: vec(3)
integer, allocatable :: idx(:)
select rank(x)
rank(2)
    idx = maxloc(x)
    vec = [q1(@idx), q2(@idx), q3(@idx)]                             
rank(3)
    idx = maxloc(x)
    vec = [q1(@idx), q2(@idx), q3(@idx)]
rank(4)
    idx = maxloc(x)
    vec = [q1(@idx), q2(@idx), q3(@idx)]
end select
end subroutine

```

Wouldn’t it make sense to submit a proposal to allow writing it like this?

```auto
subroutine max_at(x, q1, q2, q3, vec)
real, intent(in) :: x(..)
real, intent(in) :: q1(..)
real, intent(in) :: q2(..)
real, intent(in) :: q3(..)
real, intent(out) :: vec(3)
integer :: idx(rank(x))
idx = maxloc(x)
vec = [q1(@idx), q2(@idx), q3(@idx)]                             
end subroutine

```

(No allocatable, thus faster, and no `select rank` construct, thus shorter.)

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [June 10, 2021, 9:50pm UTC](https://fortran-lang.discourse.group/t/examples-for-the-new-rank-agnostic-array-notation/1376/3 "2021-06-10T21:50:40Z")

</div>

I would also prefer if it was just `q1(idx)`, but I think this syntax is already taken, I believe currently  
`q1(idx)` is equivalent to `[q1(idx(1)), q1(idx(2)), ..., q1(idx(size(idx)))]`.

I also feel this feature needs a lot more work.

---

<div class="post-metadata">

**Author:** ![Beliavsky](https://avatars.discourse-cdn.com/v4/letter/b/ba8739/32.png) [@Beliavsky](https://fortran-lang.discourse.group/u/Beliavsky)\
**Post date:** [June 10, 2021, 11:53pm UTC](https://fortran-lang.discourse.group/t/examples-for-the-new-rank-agnostic-array-notation/1376/6 "2021-06-10T23:53:41Z")

</div>

> [@pmk](#):
>
> `q1(idx)` is a vector-valued subscript applied to an assumed-rank array, which is not valid today, so it can be given a meaning without invalidating any extant code.

I also thought of suggesting this, but then `x(idx)` would have a very different meaning depending on the rank of `x`. If `x` is 1D, `x(idx)` returns the number of elements in idx, but if `x` is \>1D, `x(idx)` would return a single value. Maybe this inconsistency is worth it for a simpler syntax.

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [June 11, 2021, 3:57am UTC](https://fortran-lang.discourse.group/t/examples-for-the-new-rank-agnostic-array-notation/1376/7 "2021-06-11T03:57:03Z")

</div>

Unless the committee passes another paper that changes it, yes `@` is already determined and it will be part of 202X. However, if we don’t like it, we can propose a paper that can change the behavior.

(For the record, I voted no on this paper, I would like to see it more developed. But the majority disagreed with me.)

---

<div class="post-metadata">

**Author:** ![mfurquan](https://avatars.discourse-cdn.com/v4/letter/m/e47c2d/32.png) [@mfurquan](https://fortran-lang.discourse.group/u/mfurquan)\
**Post date:** [June 11, 2021, 5:55pm UTC](https://fortran-lang.discourse.group/t/examples-for-the-new-rank-agnostic-array-notation/1376/8 "2021-06-11T17:55:08Z")

</div>

This feature will be more useful if rank is allowed to be allocatable. For example, it can be used for generalizing ‘reduce/fold’ functions as shown below. (I have left some details for brevity.)

```auto
pure function general_reduce(binary_op,x,dim) result (r)
  real ,intent(in) :: x(..)
  integer,intent(in) :: dim
  real,allocatable :: r(..)
  integer :: i, x_shape(RANK(x)), idx(RANK(x)), idr(RANK(x)-1)
  interface
    real pure function binary_op(x,y)
      real,intent(in) :: x, y
    end function binary_op
  end interface

  x_shape = SHAPE(x)
  r = ALLOCATE(r([x_shape(:dim-1),x_shape(dim+1:)]))
  do i = 1,PRODUCT(x_shape)
    idx = counter_to_tuple(i)
    idr = [idx(:dim-1),idx(dim+1:)]
    if(idx(dim)==1) then
      r(@idr) = x(@idx)
    else
      r(@idr) = binary_op(r(@idr),x(@idx))
    end if
  end do
contains
  pure function counter_to_tuple(n) result (t)
  ! find index tuple from 1D counter. e.g. 1->(1,1,1), 2->(2,1,1) etc
    integer,intent(in) :: n
    integer :: t(RANK(x))
    ...
  end function counter_to_tuple
end function general_reduce

```

One can still achieve this Fortran by:  
a) Using PACK and RESHAPE. But, this will require memory duplication.  
b) Defining an array type. This can be as close to the proposed syntax as x.AT.[1,2,1] etc.
