Thanks. I've received the patch. I'll review it and update here when I've merged it into the library.
Given that we decided to introduce the new keyword I'll also add an engine property to disable this feature for backwards compatibility in case some older script is already using that keyword.
Was thinking, if merging of opForEnd and opForNext is possible somehow. But it is a much better UX for scripting having foreach already (I need a VS Code syntax highlighter update though :P)
I'll give it some thought but I think merging opForEnd and opForNext won't work well. At least it won't remove the need for opForEnd, which is needed to determine if the value returned by opForBegin is already beyond the end.
Thank you for merging this! And huge thanks to Henry for working on this, it is very awesome.
I have yet to play with it more, but it seems to be pretty stable so far. As for an implementation for the scriptarray addon, this does the job, if anyone needs it: (based on Henry's example, but modified to have the index as the optional second iterating value)
I can't receive my values by reference, even though opForValue returns by reference, AND I have asEP_ALLOW_UNSAFE_REFERENCES turned on:
array<string> arr = { "foo", "bar", "foobar" };
foreach (string& value : arr) {
value = "aaaa";
}
Trying to modify using auto does not work either: (is a copy being made for each value returned?)
array<string> arr = { "foo", "bar", "foobar" };
foreach (auto value : arr) {
value = "aaaa";
}
foreach (auto value : arr) {
print(value);
}
—
It would be cool if we could omit types in multiple values if they match the same type:
foreach (uint n, nn : s) {
Or even if they are different types using auto:
foreach (auto n, something : s) {
Or maybe even omitting the type altogether (implying auto), but that may be a bit too much:
foreach (n, something : s) {
—
Constness seems to be ignored for these operators:
class Constness
{
int opIndex(uint iter) { return 1234; }
uint opForBegin() { return 0; }
bool opForEnd(uint iter) { return iter == 5; }
uint opForNext(uint iter) { return iter + 1; }
uint opForValue(uint iter) { return (iter + 1) * 10; }
}
void Main()
{
const Constness b;
// Compiles fine (unexpected)
foreach (auto n : b) {
print(n);
}
// Compiler error (as expected)
int n = b[123];
}
I think I saw a TODO item about overloading not working as it should yet, so perhaps this is part of that and still on the list of things to fix. On that note, I would expect something like this to work:
Miss said: I can't receive my values by reference, even though opForValue returns by reference, AND I have asEP_ALLOW_UNSAFE_REFERENCES turned on
Returning references from the opForValue should be just fine. The issue is that AngelScript does not yet support declaring variables as references (it requires further changes to ensure the references are guaranteed throughout the life span of the variable). Even for asEP_ALLOW_UNSAFE_REFERENCES this is not available yet.
Once declaring variables as references is supported it can be made to work for foreach as well.
Miss said: is a copy being made for each value returned?
Yes, the array value is assigned to a local variable, which can then be used in the expressions within the statement block.
Miss said: Or maybe even omitting the type altogether (implying auto), but that may be a bit too much
Yes, I was actually thinking of supporting this. But it will be for a future enhancement. First I want to make sure the basic works before expanding further. 🙂
Miss said: Constness seems to be ignored for these operators:
Yes, the const overloads is something I haven't tested yet. I'll try to have that done as soon as I can.
Thanks for sharing the changes for script array add-on. I'll include this.
Also thanks informing about the syntax highlighter. I'll add a link to it on the site.
I'll be working on the dictionary add-on. I haven't decided yet on how it will be implemented.
I've now implemented the support for foreach in the script array add-on.
https://sourceforge.net/p/angelscript/code/2980/
Next I'll probably work on the foreach support for the dictionary.
--
I also gave some thought on the ability to declare the value by reference. I think I can make this work with a slightly different implementation, than an actual reference that isn't safe.
foreach( auto &v : arr )
v = v + 1;
this would be equivalent to:
for( uint iter = arr.opForBegin(); !arr.opForEnd(iter); iter = arr.opForNext(iter) )
arr.opForValue0(iter) = arr.opForValue0(iter) + 1;
So, in this case the value wouldn't be copied to a local variable. Instead, each time the value is used in an expression it will be replaced with arr.opForValue.