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

Matrix literals #102

Open
FortranFan opened this issue Nov 28, 2019 · 44 comments
Open

Matrix literals #102

FortranFan opened this issue Nov 28, 2019 · 44 comments
Labels
Clause 10 Standard Clause 10: Expressions and assignment

Comments

@FortranFan
Copy link
Member

FortranFan commented Nov 28, 2019

As proposed by a reader at comp.lang.fortran: https://groups.google.com/d/msg/comp.lang.fortran/m6qz7hC4a7M/78maOb9uEgAJ
(see the thread for further comments and discussion)

Adding matrix literals
This is mostly a quality of life thing, but something like

INTEGER, DIMENSION(2, 2) :: A = [1, 2; 3, 4]
representing the matrix
/ 1 2 \
\ 3 4 /

is, to me, a lot more readable than
INTEGER, DIMENSION(2, 2) :: A = TRANSPOSE(RESHAPE([1, 2, 3, 4], [2, 2]))
This could even be extended to more complex arrays by, for instance, repeating
semicolons, eg.
INTEGER, DIMENSION(2, 2, 2) :: B = [1, 2; 3, 4;; 5, 6; 7, 8]
One issue with this syntax is of course that the values are given row major,
which is different from the memory layout of Fortran an thus also the way
RESHAPE works.

Alternatively [1, 2; 3, 4] could represent
/ 1 3 \
\ 2 4 /
@FortranFan FortranFan changed the title Let the ALLOCATE statement check if variables are already ALLOCATED Matrix literals Nov 28, 2019
@certik
Copy link
Member

certik commented Nov 28, 2019

Yes! I've been wishing something like this for years.

@jacobwilliams
Copy link

Agreed. The reshape thing is not ideal. I wish there was some way to declare a matrix that didn't require you to know that the compiler was using column major order. That always seemed to me a low-level detail that a user shouldn't have to know about.

@LKedward
Copy link

Agreed. The reshape thing is not ideal. I wish there was some way to declare a matrix that didn't require you to know that the compiler was using column major order. That always seemed to me a low-level detail that a user shouldn't have to know about.

Not sure about this.
I wouldn't use a language if I couldn't be sure about the storage layout of higher dimension arrays.
It's absolutely necessary to know storage layout a priori in order to ensure memory access is contiguous and therefore efficient.
Performance difference between strided access and contiguous access is very significant.

Otherwise I agree with the usefulness of matrix literals.

@jacobwilliams
Copy link

Sure, for performance you need to know that. But for showing a beginner how to declare a 3x3 matrix parameter it's not really that great.

@certik
Copy link
Member

certik commented Nov 28, 2019 via email

@LKedward
Copy link

Sure, for performance you need to know that. But for showing a beginner how to declare a 3x3 matrix parameter it's not really that great.

Agreed, I'd interpreted your sentiment as a more general desire to completely abstract away storage order to compiler implementation.

@gronki
Copy link

gronki commented Nov 28, 2019 via email

@LKedward
Copy link

I wish there was some way to declare a matrix that didn't require you to know that the compiler was using column major order.

But for showing a beginner how to declare a 3x3 matrix parameter it's not really that great.

With these things being said, and returning to the last point in the original post, there is an argument for using row-major in the literal syntax in that it is the same as MATLAB and therefore will be familiar to beginners coming from MATLAB.
Indeed, I understand that MATLAB uses row-major syntax despite being column major storage.

@LKedward
Copy link

MATLAB also accepts commas as column delimiters instead of spaces and this is generally recommended for readability.

i.e. The following are equivalent in MATLAB

a = [1 2 3; 4 5 6; 7 8 9];
a = [1, 2, 3; 4, 5, 6; 7, 8, 9];

It is the same comma/semicolon syntax as suggested in the original post.

An alternative syntax not using the semicolon could be nested array literals:

integer :: a(3,3)
a = [[1,2,3],[4,5,6],[7,8,9]]

but this again raises the row-major/column-major syntax question.

@jacobwilliams
Copy link

jacobwilliams commented Nov 28, 2019

I certainly think that the limitations of fixed-form source should not enter the deliberations. It's long past time for that to be eliminated (#108).

@rweed
Copy link

rweed commented Dec 7, 2019

After spending several days recently typing in data to create equation of state tables, I can say from experience that anything like the MATLAB way of defining multi-dimensional arrays would be a big improvement over RESHAPE. I've never understood why you need RESHAPE if you are entering data in column major order in the first place.

@sblionel
Copy link
Member

sblionel commented Dec 9, 2019

I could certainly see relaxing the shape matching rules if the right side was a rank-1 array with the same SIZE as the left. I do wonder how these proposals would extend to rank 3 and greater arrays.

@zjibben
Copy link
Member

zjibben commented Jan 4, 2020

An existing alternative I haven’t seen mentioned here is using a data statement:

integer :: A(2,2)
data A /1,2,  3,4/

This isn’t as nice as the proposed syntax, and there’s still the row/column ordering issue, but I tend to find it slightly more readable than reshape. Having everything on one line would be even better.

@FortranFan
Copy link
Member Author

@zjibben wrote:

An existing alternative I haven’t seen mentioned here is using a data statement:

integer :: A(2,2)
data A /1,2,  3,4/

I've avoided DATA statements in any code I wrote and I've shied away from ever recommending DATA statements because it attaches the perilous "implied SAVE" attribute to objects in Fortran:

From the standard:

8.6.7 DATA statement
..
.. a named variable has the SAVE attribute if any part of it is initialized in a DATA statement ..

@zjibben
Copy link
Member

zjibben commented Jan 5, 2020

@FortranFan That is a very good point, and probably why I’ve only seen it used for constant module-level data..

@urbanjost
Copy link

urbanjost commented Jan 8, 2020

Some initial thoughts. If:

integer,save :: xx(3,5)= reshape([&
1, 2, 3, 4, 5, &
10,20,30,40,50, &
11,22,33,44,55 &
],shape(xx),order=[2,1])

where equivalent to the simpler (order= on LHS implies :
the type of RESHAPE above):

  integer(order=[2,1]),save :: xx(3,5)= [&
   1, 2, 3, 4, 5, &
  10,20,30,40,50, &
  11,22,33,44,55  &
  ]

I would be happy, although I am not sure it
would be what I would call intuitive to a new
user. Would be nice to not need the & too, but that would break a lot of other rules.

ALTERNATIVE 1
Nesting or grouping with brackets would look
the nicest, but not as explicit past three
degrees. for 2-D maybe something like:

  integer,save :: xx(3,5)= &
  [ 1, 2, 3, 4, 5], &
  [10,20,30,40,50], &
  [11,22,33,44,55],

would be nice. That would still work for
space dimensions and still look clean.

  integer,save :: xx(3,5,2)= &
  [ 1, 2, 3, 4, 5], &
  [10,20,30,40,50], &
  [11,22,33,44,55], &

  [ 1, 2, 3, 4, 5], &
  [10,20,30,40,50], &
  [21,22,33,44,55]  &

ALTERNATIVE 2
Taking some of the syntax from DATA statements could be a
general solution. Maybe instead of

! fill rows using DATA statements
integer,save,dimension(3,5) :: gg
data gg(1,:)/  1,  2,  3,  4,  5 /
data gg(2,:)/ 10, 20, 30, 40, 50 /
data gg(3,:)/ 11, 22, 33, 44, 55 /

could become:

integer,save,dimension(3,5) :: gg=[[ (1,:)/  1,  2,  3,  4,  5 / &
                                    (2,:)/ 10, 20, 30, 40, 50  / &
                                    (3,:)/ 11, 22, 33, 44, 55 / ]]
where the redundant brackets flags to use "DATA" format?

DATA statements are so flexible and do not have problems like a limit
on the number of continuation lines and so on. The implied SAVE never
caused me any issues, it was the "feature" that you do not to have to
initialize all the values that made me careful with DATA statements.

DIdn't do a proof on whether the synax would work generically with 
dimensions higher than space dimensions, but I will work it out if anyone 
thinks those syntax's are appealing.


An option to print small arrays in the same format would be nice
too, like dispmodule(3f), "A Fortran 95 module for pretty-printing
matrices". ([email protected]).


     

@aradi
Copy link
Contributor

aradi commented Jan 8, 2020

I could certainly see relaxing the shape matching rules if the right side was a rank-1 array with the same SIZE as the left. I do wonder how these proposals would extend to rank 3 and greater arrays.

That sounds to me like a very pragmatic solution! Since we can let multi-rank pointers point to rank-1 targets, one could similarly allow the assignment of a rank-1 array to a multidimensional array, provided, the shape of the LHS is known (so not automatic reallocation occurs).

We could then write:

integer :: array2(2, 2) = &
  & [ 1, 2, &
  &   3, 4 ]

integer, array3(2, 2, 2) = &
  & [ 1, 2, &
  &   3, 4, &
  &&
  &  5, 6, &
  &  7, 8 ]

I dont't think, that the other proposed forms (introducing new symbols) are much more readable than those examples. Actually, using Fortran's array-merging strategy one could even write:

  integer :: array(2, 2, 2) = &
      & [[[ 1, 2 ], &
      &   [ 3, 4 ]], &
      &  [[ 5, 6 ], &
      &   [ 7, 8 ]]]

which is on par with any other notations suggested so far. You would still have to remember, that Fortran has column-major ordering (so lines in the literal correspond to 'columns' in the actual array), but that is IMO acceptable.

@certik
Copy link
Member

certik commented Jan 8, 2020

I like this syntax the most:

integer :: a(3,3)
a = [[1,2,3], [4,5,6], [7,8,9]]
print *, a

That's how Python does it. As @septcolor mentioned in #102 (comment), currently Fortran flattens such arrays. What is the motivation for this "flattening"?

I think rethinking this and allowing the natural a = [[1,2,3], [4,5,6], [7,8,9]] syntax would be the best.

@aradi
Copy link
Contributor

aradi commented Jan 8, 2020

@certik If the assignment of rank-1 arrays to rank-N arrays were allowed, your example would work immediately without the need for any backwards incompatible changes. As long as the shape of the LHS is unambigous, the flattening of the literal of the RHS won't be an issue.

We would only have troubles with automatic reallocation, such as

integer, allocatable :: a(:,:)
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

as here it is impossible to find out, how RHS should be reshaped to match LHS. For those cases, the compiler would have to emit an error and stop.

@certik
Copy link
Member

certik commented Jan 8, 2020

I see. I still think removing this automatic "flattening" would help. What is the motivation for it? We can introduce a function flatten, that can do this flattening if you really want it:

a = flatten([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

But otherwise it should not flatten by default in my opinion.

@aradi
Copy link
Contributor

aradi commented Jan 8, 2020

Well, removing the flattening would be backwards incompatible, as the following code snippet won't work any more:

program test
  implicit none

  integer, allocatable :: a(:), b(:)

  a = [1, 2]
  b = [a, a]
  print *, b

end program test

@certik
Copy link
Member

certik commented Jan 8, 2020

True. But this would work:

program test
  implicit none

  integer, allocatable :: a(:), b(:)

  a = [1, 2]
  b = flatten([a, a])
  print *, b

end program test

I agree since this is backwards incompatible, we might not want to do that. But if the only motivation for automatic flattening is backwards compatibility, then it would seem this was a bad design decision long time ago.

@aradi
Copy link
Contributor

aradi commented Jan 8, 2020

Unfortunately, it is not just flattening, but also automatic merging. The assignment

b = [[-3, 2, 9], [1, 2]]

currently works (provided b is a rank-1 array), but it would became a syntactical non-sence if the braces would open/close ranks as they do in Python.

I agree, that the current syntax is weird and I have no clue, why it was introduced. But I don't think we have any chance to delete it from the language. So, the best compromise IMO is still the assignment of rank-1 arrays to rank-N ones without the need for a reshape, as suggested by @sblionel .

@eprovst
Copy link

eprovst commented Nov 2, 2020

But I don't think we have any chance to delete it from the language.

Given that I used this rather recently, that chance is indeed rather slim. It's convenient to concatenate arrays, although an intrinsic function would have been the better choice back when that syntax was introduced.

I'm still keen on doing something similar to Matlab or Julia as in my initial proposal (I'm the original comp.lang.fortran poster), but I haven't yet found a better alternative.

I'd be weary of introducing anything that doesn't also scale to rank 3 (or higher) arrays, though.

@certik
Copy link
Member

certik commented Nov 2, 2020

@elecprog thanks for the feedback and for the proposal. I think there is still an opportunity here to do something, but we have to figure out how to do it to satisfy all the requirements/issues stated in this thread.

@urbanjost
Copy link

urbanjost commented Nov 3, 2020

When I think of all the capabilities available in READ() including list-directed and implied DO constructs if there were some equivalent of a "here" document in Fortran it woud allow for inputting small arrays but also text blocks without having to use continuation characters and quotes as well.

integer :: a(3,4) <<< read(*,*)(a(i,j),i=1,3,j=1,4)
   1  2   3   4
   5  6   7   8
   9  10  11  12
>>>

character(len=:),allocatable :: text(:) <<< read(*,'(a)')text
   This is the help text
   for my
   program
>>>

Almost no new syntax, useful for small arrays but maybe more so for text; would be really nice to have some kind of block comment too, maybe just

<<<
   a block of
   text
>>>

@eprovst
Copy link

eprovst commented Sep 13, 2021

Maybe we could take some inspiration from the syntax introduced in Julia v1.7 (see NEWS.md).

A first thing to note in Julia's case, [1, 2, 3] is a (column) vector (in Fortran terms dimension(3)) and [1 2 3] is a row vector (in Fortran terms dimension(1, 3)).

A ; concatenates in the column direction, i.e. [1; 2; 3] == [1, 2, 3]. Since v1.7 this idea is extended to repeated semicolons concatenating in the next dimension, thus [1;; 2;; 3] == [1 2 3] (the row is the second dimension), etc.

Julia does not allow mixing of commas and semicolons, but it does allow spaces and semicolons, giving for example: [1 2 3; 4 5 6] == [[1 2 3]; [4 5 6]] thus the matrix shorthand is nothing but the concatenation of two row vectors along the column (= first) direction. Another way to write the exact same matrix would be [1; 4;; 2; 5;; 3; 6] == [[1, 4] [2, 5] [3, 6]] where we write the matrix as the horizontal concatenation of three column vectors (which evidently is also how the memory layout of Fortran thinks about matrices).

Which is also another motivation of the automatic flattening as this is also how it's written in mathematics (using newlines for concatenation in the column direction instead of semicolons 😉)

Fortran already has a concatenation operator // which could extend to /// etc. But I do not yet know how if feel about [1 2 // 3 4] == [1 // 3 /// 2 // 4].

@certik certik added the Clause 10 Standard Clause 10: Expressions and assignment label Apr 23, 2022
@PierUgit
Copy link
Contributor

PierUgit commented Feb 18, 2023

The problem is quite simple if one simply wants an intuitive way to write matrices (aka rank 2 arrays). The semicolumn ; looks a simple and convenient way to do that, and it would be the same as in Matlab

integer :: array(2, 3) = [1, 2, 3 ; 4, 5, 6]
! would be really the matrix
!   / 1  2  3 \
!   \ 4  5  6 /

A general mechanism to concatenate arrays of arbitrary ranks and along arbitrary dimensions is something that goes far beyond the initial motivation of the proposal... Such a mechanism can hardly be simple and fully intuitive on the one hand, and we generally don't need to intuively write rank 3 (or more) arrays like we do for a matrix.

@rweed
Copy link

rweed commented Feb 18, 2023

I can live with @PierUUs solution. I am still curious as to why the standard requires you to use RESHAPE instead of just assuming that you want to map the data in the rank 1 initializer to the the column major order of the target array. ie.

``
integer :: array(2,3) = [1,2,3,4,5,6]

! should just map to
| 1 3 5 |
| 2 4 6 |
``
without having to use RESHAPE

@PierUgit
Copy link
Contributor

Indeed. You need to know the memory layout to write performant code, but it should not be necessary to know the layout just to write correct code (even if slow).

I tend to disagree here: Fortran is traditionnally THE langage for HPC, and performance should be at the core of it. And the sooner the beginners learn about memory layout and its consequences, the better.

It's actually not only about performances (after all, on some hardware the memory layout doesn't matter), it also helps understanding some behaviours (e.g. how a rank 2 array can be associated to a rank 1 array...)

@FortranFan
Copy link
Member Author

Fortran is traditionnally THE langage for HPC

A much. much, much longer "tradition" with Fortran is "formula translation" for the programmer and for the processor to then adopt to it in a performant manner. Let us not place the cart before the horse here.

@PierUgit
Copy link
Contributor

What I essentially say is that the cart and the horse should be placed at the same time. The by far best programming course I got, a long time ago, did not teach me any language syntax, but how a computer was computing under the hood, "when you do that in your high level langage, here is what really happens in the chips"

@PierUgit
Copy link
Contributor

PierUgit commented Feb 19, 2023

`` integer :: array(2,3) = [1,2,3,4,5,6]

! should just map to
! | 1 3 5 |
! | 2 4 6 | ``
without having to use RESHAPE

I also agree. At some point we got the flexibility in the language to have a rank-N pointer pointing to a rank-1 array, so have the same kind of flexibility to assign a rank-1 array to a rank-N array looks reasonnable (the downside is that no more error-checking would be possible for such an assignement by mistake). This doesn't solve the "by row" notation, though, and

integer :: array(2,3) = [1,2,3 ; 4,5,6]
! / 1 2 3 \
! \ 4 5 6 /

Would make sense in addition. For those who think that a notation that doesn't gracefully generalize to any arbitratry rank is not wishable, one could think about a notation that would make clear that this is an exception for matrices. For instance:

integer :: array(2,3) = matrix([1, 2, 3],[4, 5, 6])

The matrix intrinsic function would accept any number of rank-1 arrays expressing rows:

matrix(row1 [,row2 [,row3 ...]])

@aradi
Copy link
Contributor

aradi commented Feb 19, 2023

Note, that if you are OK with column-wise notation (instead of row-wise notation), the change suggested by @rweed is enough and would provide a solution for arbitrary ranks, as Fortran automatically flats embedded arrays into a 1D array:

program test
  implicit none

  integer :: array(8)
  ! integer :: array(2, 2, 2)

  array(:) = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
  ! array(:, :, :) = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]  ! not working yet
  print *, array

end program test

@PierUgit
Copy link
Contributor

Note, that if you are OK with column-wise notation

To me, a column-wise notation is almost pointless: if one wants a notation that is intuitive, it has really to mimic how matrices are usually written, i.e. row-wise (and the original post of this discussion is all about row-wise, btw).

! array(:, :, :) = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] ! not working yet

But as discussed above, this would not be backward compatible with the current standard.

@FortranFan
Copy link
Member Author

FortranFan commented Feb 20, 2023

What I essentially say is that the cart and the horse should be placed at the same time. The by far best programming course I got, a long time ago, did not teach me any language syntax, but how a computer was computing under the hood, "when you do that in your high level langage, here is what really happens in the chips"

The notion someone may carry Fortran "is traditionnally THE langage for HPC" or how one was taught is not at all pertinent to the discussion in this thread as to the easier options the language can offer with writing out matrix literals.

The language currently offers

    ..
    .. = reshape( [ .. xx, yy, zz, .. ], shape=.. )
    ! or 
    .. = reshape( [ .. xx, yy, zz, .. ], shape=.. , order=[..] )
    .

Having easier, literal ways to write out the matrix than having to use RESHAPE will be good for Fortran to consider and there is no relevance to memory layout beyond what is already considered in RESHAPE.

@rweed
Copy link

rweed commented Feb 20, 2023

My initial idea for handling row-wise vs column wise would be to add an attribute for arrays of intrinsic type that specifies row-wise storage. Something like

integer, storage = "ROW_WISE" :: a(2,3) = [1,2,3,4,5,6]

Unfortunately on further thought I can see this causing a lot of issues with optimization, vectorization etc and would force the compiler developers to make major changes to their existing array handling code. To bad because on the surface I think (from a syntax standpoint at least) being able to specify storage order might be a simple way to eliminate (or at least reduce) the need for RESHAPE and or TRANSPOSE for defining arrays.

@certik
Copy link
Member

certik commented Feb 20, 2023

Probably this syntax is more natural: integer, layout(col_major) :: a(2,3) = [1,2,3,4,5,6], or layout("col_major"). I think arrays need this attribute anyway, to become on par with NumPy and C++/Kokkos. However that's probably a separate question.

Why couldn't

array(:, :, :) = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] 

always mean row major, even if internally the array is stored as column major? This is all compile time, so the compiler can rearrange things appropriately to be efficient. There are backwards compatibility issues, but I still think the above would be the most natural and Fortran almost can do it. It would be very nice if it could do it completely.

@PierUgit
Copy link
Contributor

...is not at all pertinent to the discussion in this thread...

  1. It's not because you don't share this point of view that it makes it "not pertinent"; 2) In this discussion I'm not the one who initially raised the internal layouts and performance concerns.

Having easier, literal ways to write out the matrix than having to use RESHAPE will be good for Fortran to consider

Where did I write it wouldn't?

@urbanjost
Copy link

Note the ifort compiler appears to implement allowing a vector on the LHS to fill an array on the RHS of any defined shape
if anyone wants to try that;
and that there are intrinsics to flatten an array. See pack(3f) and unpack(3f).

program testit

logical, parameter :: T=.true., F=.false.

!integer :: ii(3, 2) = reshape([(i, i=1, size(ii))],shape=shape(ii))
integer  :: ii(3, 2) = [(i, i=1, size(ii))]

   write(*,*)rank(ii),shape(ii)
   call printi('ii=', ii)
   call printi('[ii]=', [ii])             ! flattens it
   call printi('pack(ii,T)=', pack(ii,T)) ! flattens it
contains

subroutine printi(title,a)
implicit none
!@(#) print small 2d integer scalar, vector, matrix in row-column format
character(len=*),intent(in)  :: title
integer,intent(in)           :: a(..)
character(len=*),parameter   :: all='(" ",*(g0,1x))'
character(len=20)            :: row
integer,allocatable          :: b(:,:)
integer                      :: i
   write(*,all,advance='no')trim(title)
   ! copy everything to a matrix to keep code simple
   select rank(a)
   rank (0); write(*,'(a)')' (a scalar)'; b=reshape([a],[1,1])
   rank (1); write(*,'(a)')' (a vector)'; b=reshape(a,[size(a),1])
   rank (2); write(*,'(a)')' (a matrix)'; b=a
   rank default; stop '*printi* unexpected rank'
   end select
   ! find how many characters to use for integers
   write(row,'(i0)')ceiling(log10(real(maxval(abs(b)))))+2
   ! use this format to write a row
   row='(" > [",*(i'//trim(row)//':,","))'
   do i=1,size(b,dim=1)
      write(*,fmt=row,advance='no')b(i,:)
      write(*,'(" ]")')
   enddo
   write(*,all) '>shape=',shape(a),',rank=',rank(a),',size=',size(a)
   write(*,*)
end subroutine printi

end program testit

@klausler
Copy link

Probably this syntax is more natural: integer, layout(col_major) :: a(2,3) = [1,2,3,4,5,6], or layout("col_major"). I think arrays need this attribute anyway, to become on par with NumPy and C++/Kokkos. However that's probably a separate question.

Why couldn't

array(:, :, :) = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] 

always mean row major, even if internally the array is stored as column major? This is all compile time, so the compiler can rearrange things appropriately to be efficient. There are backwards compatibility issues, but I still think the above would be the most natural and Fortran almost can do it. It would be very nice if it could do it completely.

The right-hand side of your sample assignment statement already has a conforming interpretation, so that syntax is not an option.

@certik
Copy link
Member

certik commented Feb 21, 2023

The right-hand side of your sample assignment statement already has a conforming interpretation, so that syntax is not an option.

Unfortunately the syntax is already taken, so this is indeed not an option without breaking compatibility. :(

@Sandwich-X
Copy link

Sandwich-X commented Jul 9, 2023

array(:, :, :) = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

The right-hand side of your sample assignment statement already has a conforming interpretation, so that syntax is not an option.

Therefore, as already mentioned above, this could do it:

array(:, :, :) = [ [ [1, 2] ; [3, 4] ] ; [ [5, 6] ; [7, 8] ] ]

{EDIT2: as ";" is also the comand-separator, this could make source-code parsing more difficult.}

or

array(:, :, :) = [ [ [1, 2] / [3, 4] ] / [ [5, 6] / [7, 8] ] ]

as "/" stands for "new line" in format descriptors,

{EDIT1: this conflicts with division}

or

array(:, :, :) = [ [ [1, 2] | [3, 4] ] | [ [5, 6] | [7, 8] ] ]

{EDIT3:

or

array(:, :, :) = [ [ [1, 2] | [3, 4] ] || [ [5, 6] | [7, 8] ] ]

to make rank-separation more clear

}

or with any other "meaningful" character

{EDIT4: e.g. "#", "^", "$", ... if there is no other possible conflict.}

@urbanjost
Copy link

The slash / syntax also has a current interpretation

open main.f90 in Fortran Playground

program main
implicit none
  write(*,*) [ [ [1000, 2000] / [3, 4] ] / [ [500, 600] / [7, 8] ] ]
end program main
           4           6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Clause 10 Standard Clause 10: Expressions and assignment
Projects
None yet
Development

No branches or pull requests