Insert API for lists || Poll

Hope you are doing well,

I was working on lists (string list) and realised that python uses INSERTING BEFORE option but I personally found INSERTING AT as the most intuitive one.

Which one of the 3 behaviours do you prefer (based on your own terms) from insert function for lists:

  • INSERTING AFTER: Insert the new element after ( i )-th index
  • INSERTING BEFORE: Insert the new element before ( i )-th index
  • INSERTING AT: Insert the new element at ( i )-th index, so that after insertion is done newly added element is at ( i )-th index [irrespective of ( i ) being a forward or backward index]

0 voters

Please Note: There is NO difference between INSERTING BEFORE and INSERTING AT when it comes to forward indexes.
Similarly, there is NO difference between INSERTING AFTER and INSERTING AT when it comes to backward indexes.

let’s take an example:
list = [ ‘a’, ‘b’, ‘c’, ‘d’, ‘e’ ] (I am considering 1 based indexing in both forward and backward directions here i.e. first element is at index 1 and last element is at index -1)


Inserting at FORWARD index 3

insert_after( list, index = 3, new_element = ‘new element’ )
—> [ ‘a’, ‘b’, ‘c’, ‘new element’, ‘d’, ‘e’ ]

insert_before( list, index = 3, new_element = ‘new element’ )
—> [ ‘a’, ‘b’, ‘new element’, ‘c’, ‘d’, ‘e’ ]

insert_at( list, index = 3, new_element = ‘new element’ )
—> [ ‘a’, ‘b’, ‘new element’, ‘c’, ‘d’, ‘e’ ]


Inserting at BACKWARD index 2

insert_after ( list, index = -2, new_element = ‘new element’ )
—> [ ‘a’, ‘b’, ‘c’, ‘d’, ‘new element’, ‘e’ ]

insert_before ( list, index = -2, new_element = ‘new element’ )
—> [ ‘a’, ‘b’, ‘c’, ‘new element’, ‘d’, ‘e’ ]

insert_at ( list, index = -2, new_element = ‘new element’ )
—> [ ‘a’, ‘b’, ‘c’, ‘d’, ‘new element’, ‘e’ ]

1 Like

FYI, Fortran doesn’t have negative indexing, so whatever you choose will possibly be un-intuitive for many users. The reason being that Fortran allows one to choose the starting and ending indices of an array. Note also that Fortran doesn’t preserve the bounds in many instances as well, so you’ll have to be quite careful in designing the API for this one. As an example:

integer, dimension(-2:2) :: my_array
integer, dimension(:), allocatable :: alloc_array

my_array = [-2, -1, 0, 1, 2] ! This preserves the original bounds
print *, my_indexer(my_array, 1), my_array(1) ! this will print "-2 1"

allocate(alloc_array(-2:2))
alloc_array = [-2, -1, 0, 1, 2] ! This should preserve the bounds, as it is the same size
print *, my_indexer(my_array, 1), my_array(1) ! this should print "-2 1"

deallocate(alloc_array)
allocate(alloc_array(-2:2))
alloc_array = [-2, -1, 0, 1, 2, 3] ! This won't preserve the bounds, as it will trigger automatic (re)allocation on assignment due to different size
print *, my_indexer(my_array, 1), my_array(1) ! this should print "-2 -2"
contains
  function my_indexer(array, index_) result(val)
    integer, intent(in) :: array(:) ! This doesn't get the original bounds, so will be (1:size(array))
    integer :: val

    val = array(index_)
  end function
end program

So the question becomes, what does this mean?

integer, allocatable :: my_array(:)

allocate(my_array(-2:2))
my_array = [-2, -1, 0, 1, 2]
my_array = insert(my_array, index = -1, new_element = 3) ! [-2, 3, -1, 0, 1, 2] or [-2, -1, 0, 1, 3, 2]
4 Likes

Thanks Brad, backward indexing is already quite controversial (see this comment)

Currently I am not planning to let the user give custom indexes and if we agree to include that feature later someday, the current design will come to be quite handy to build upon to provide custom indexes but for now I am just looking forward to get a simple working string list into stdlib.

The design that I am currently working on (Pull Request: #470) differentiates unambiguously between forward indexes and backward indexes because I am not using integers as indexes rather I am using a custom data type as an index which asks user if it is a forward index or a backward index (taking inspiration from @Arjen’s idea of using custom data types to represent head and tail of lists). And surprisingly (as of now) there are NO integer indexes like -2, 3, etc as mentioned in the example of the post.

So, if a user says forward_index (x) the API will never confuse it with any of the backward_indexes. It’s like 2 traffic lanes (one from left to right [forward index] and other from right to left [backward_index]) running parallely and not conflicting with each other. Let’s see how well it is received by the community.

@everythingfunctional, the API under discussion here is for a derived type representing a list of string and not built-in (integer) allocatable arrays.

It would be nice if the associate construct could be used to recover the index object of each string list.

Would it be possible to split the argument index into three optional arguments called before, after and at?

1 Like

I see. I’ll have to look at the PR, but it sounds like I won’t have be too worried about it. I like the idea of having forward and backward indices being different types. I’ve done something like that before, using 2 new types to distinguish between what would ordinarily be easy to mix up.

In MATLAB one can create or extend an array by inserting at any position:

>> exist('list','var')

ans =

     0

>> list(2) = 2

list =

     0     2

>> list(4) = 4

list =

     0     2     0     4