ID:132730
 
It would be really convenient to be able to access indexes from the list from the right to the left using negative indexes. Python already uses this method, and it makes a lot of things easier. It'd also be even greater if you were able to index text strings as well.

So basically, when you want to reverse a list's indexes:
var/l[0]
for( var/x = 1 to list.len )
l += list[-x]
list = l

And as for being able to index single characters in text strings, it would certainly cut down on the code you'd have to write. You could replace ascii2text( text2ascii( text, x ) ) or copytext( text, x, x+1 ) with a simple text[x].

Though I know it's 'low priority', it still seems a nice feature, maybe for a future release?
var/l[0]
for( var/x = 1 to list.len )
l += list[list.len-x]
list = l

Wouldn't that work or did I read that wrong.
In response to Leur (#1)
Not as well as this:

<DM>var/l[0]
for( var/x = list.len to 1 step -1 )
l += list[x]
list = l
In response to Garthor (#2)
I'm well aware of both those methods, and they both work well enough. This is just a consolation feature that would be convenient to have.
Personally, I wouldn't like this- but if we had operator overloading, everyone can go with their own preference!
In response to Airjoe (#4)
Operator overloading was already turned down because it would make DM too complex :(
Metamorphman wrote:
It would be really convenient to be able to access indexes from the list from the right to the left using negative indexes

That adds nothing new, and could create issues, so there isn't really any point in adding this. Presently negative indexes are invalid so will generate an error, with this feature when an index is accidentally set below 0, then instead of generating a runtime error, easily indicating the problem, you'd get "funny" (unintended) results. Not particularly worth adding a convenience feature to save you from needing to subtract from len.

And as for being able to index single characters in text strings, it would certainly cut down on the code you'd have to write. You could replace <code>ascii2text( text2ascii( text, x ) )</code> or <code>copytext( text, x, x+1 )</code> with a simple text[x].

Cutting down on actual code that needs to be written already isn't a problem.
#define c(t,p) copytext(t,p,p+1)
mob/verb/output_a()
src << c("123a45",4)

It's not needed, though, either.
I don't see how that would make anything better, and how is that even supposed to work anyway? Does array alement -1 reference the same thing as the last element and element at negative-size reference the same thing as element 1?
In response to Loduwijk (#7)
Loduwijk wrote:
Does array alement -1 reference the same thing as the last element and element at negative-size reference the same thing as element 1?

Pretty much as far as I can tell. It would be neat to have this though, since it would avoid some overhead done by math in some cases.

Would be totally awesome if it'd work for strings too. Perhaps even with L[2:5] to combine multiple entries together (if it's a string or a number).
In response to Android Data (#8)
The math overhead is so little it isn't really worth it, though. Not to mention you're getting weird logic errors rather than runtime errors if you screw up.
I'm not sure negative list indexes would make a lot of sense for general purposes, but the ability to use negative indexes in certain string functions like copytext() or such would be highly useful. In theory that wouldn't break any existing code that isn't already broken.

Indexing strings is an interesting idea, but it would probably have to be read-only. The reason is that if you used something like str[2]="b", the string referenced by str would not change (though it might be destroyed if it's no longer in use). Instead a new string would be created to make the assignment, or an existing string matching the new one would have its reference count increased. So the value inside the str var would have to change in order for you to keep using it; that may not be so doable. I wouldn't be surprised if I could figure out how to index a string, but changing the var I'd be indexing would be a different matter.

Lummox JR
In response to Jeff8500 (#9)
I think I agree with Jeff on this one. Index out of bounds should be just that: index out of bounds.

Also, what is Byond going to do with index 0? You can go from -len to len but have to skip over 0?

I think a better option for people that want this is to make their own wrapper for this.
ReflectedArray
var/list/reflectedList[0]
var/len = 0

proc
Add()
for(var/x in args)
reflectedList.Add(x)
len = reflectedList.len

Remove()
for(var/x in args)
reflectedList.Remove(x)
len = reflectedList.len

Get(index)
if(index < 0)
index = reflectedList.len - index + 1
return reflectedList[index]

Replace(index, element)
if(index < 0)
index = reflectedList.len - index + 1
reflectedList[index] = element

Swap(index1, index2)
if(index1 < 0)
index1 = reflectedList.len - index1 + 1
if(index2 < 0)
index2 = reflectedList.len - index2 + 1

reflectedList.Swap(index1, index2)

Insert()
var/i
for(var/x in args)
if(i == null)
i = x<0 ? reflectedList.len-x+1 : x
continue
reflectedList.Insert(i++, x)

len = reflectedList.len

Copy(start = 1, end = 0)
if(start < 0)
start = reflectedList.len - start + 1
if(end < 0)
end = reflectedList.len - end + 1

return reflectedList.Copy(start, end)

Cut(start = 1, end = 0)
if(start < 0)
start = reflectedList.len - start + 1
if(end < 0)
end = reflectedList.len - end + 1

var/list/L = reflectedList.Cut(start, end)
len = reflectedList.len

return L

Find(Elem, start = 1, end = 0)
if(start < 0)
start = reflectedList.len - start + 1
if(end < 0)
end = reflectedList.len - end + 1

return reflectedList.Find(Elem, start, end)

setLen(len)
reflectedList.len = len
src.len = len

Use that, and it works for the most part like a normal list with the additions that were asked for. The differences are as follows:

You cannot use [] brackets to directly access elements. Instead, you use the Get() and Replace() functions, so it looks like list.Get(5) instead of list[5] or Replace(5, new /obj) instead of list[5] = new /obj

You cannot change the size of the array by directly changing len, in fact you should never directly change len. Instead, you can use the setLen() function provided and it will have the exact same functionality as setting the list's len variable.

This does not support multi-dimensional lists nor does it support assossiative lists, though you could probably extend it to do so if you so chose.

If you want to use the "in" operator (or its kind, such as locate()), you have to do it on the list that backs the data structure instead of on the object itself. For example, if youw ant to loop through all mobs in it, you cannot do for(var/mob/M in specialArray) but instead you would have to do for(var/mob/M in specialArray.reflectedList)

So there are a few minor syntax changes in some situations, but the only functionality lost by the above code is multi-dimensional lists and assossiative lists. Everything else I can think of at the moment is preserved, and most of it still works exactly the same as a normal list.