SVN version of DWScript adds a long-missing functionality in DWS: dynamic arrays. They provide a language-based alternative to the list and collections classes that had to be used so far.
They extend the “new” keyword for instantiation, and introduce pseudo-method semantics in addition to the traditional semantics for Low(), High() and Length().
var a : array of Integer; var i : Integer; a := new Integer[10]; for i := a.Low to a.High do a[i] := i;
The pseudo-methods currently available on dynamic arrays are:
- Low, High, Length: lower bound, higher bound and item count respectively.
- SetLength(n): adjust the number of items of an array.
- Add(item) : add an item to an array.
- Delete(index[, count]) : deletes one or more items from an array.
- Copy([index[, count]]) : creates a new array that holds a (shallow) copy of the items, there are three forms:
- Copy() copies the whole array
- Copy(index) copies all items starting from index
- Copy(index, count) copies count items starting from index
- Swap(index1, index2) : swaps the items at the specified indexes
Dynamic arrays in DWS are pure reference types and they behave a bit like a TList<T> would in Delphi, as SetLength() is a method, which modifies the array, rather than a global procedure, which can create a new copy of the array (as in Delphi), ie. in DWScript, if you have:
var a, b : array of Integer; a := new Integer[5]; b := a; a[1] := 1; PrintLn( b[1] ); a.SetLength(10); a[1] := 2; PrintLn( b[1] );
It will print 1 and 2. A Delphi version using “SetLength(a, 10)” instead would print 1 and 1.
In other words, in DWScript, if you want a new dynamic array instance, you use “new”, if want to make a copy of a dynamic array, you have to use .Copy(), if you want to resize, you use .SetLength(). Whereas in classic Delphi, all three aspects are behavioral variants of the SetLength() global procedure.
Note that if the dynamic arrays in DWS currently rely on compiler magic, there is a long term goal of having them mappable to a “regular” generic container class.
What if I have a Record/Class in an array with a property and/or Field that matches one of the new pseudo-methods. Which will take precedence? How to I disambiguate and select one or the other?
@Robert Love
The pseudo-method is applied to the array, your record/class would be an element, ie. “a.Thing” applies to the array (seen as an entity), while “a[index].Thing” applies to an element (your class or record).
Thank you very much, I had to bypass this limit using bad approaches, THANK YOU!!
Or put another way, write code that works one way in Delphi but which works completely differently in DWS.
Of course, to be fair, the syntax is different too, so you can’t literally write code that even runs in both environments, but the point never-the-less remains.
I can’t say that I ever came across this “I modified the length of an array and now a reference that I took to it earlier references some older copy of that array” problem.
Maybe I’ve just been lucky in 15+ years of Delphi ?
@Robert – as Eric points out, I’m not sure where the possibility for confusion arises. If you have a record/object in an array then:
a.Delete(n) // deletes the n’th element of a
Cannot easily be confused with:
a[i].Delete(n) // calls the delete(n) method of the i’th element of a
At least, imho. ymmv. 🙂
@Jolyon Smith
Well the issue you’ve not come across in 15+ years of Delphi is one I’ve seen developers come across, until they learn better and go for some T*List alternative. I’ve alsa certainly seen assignment + SetLength() being used to copy an array.
Not that in the DWS syntax, you can introduce an ambiguous SetLength() procedure for backward compatibility if you want, its implementation would be like: