-
-
Notifications
You must be signed in to change notification settings - Fork 376
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
For each index & value loop. #6562
Conversation
I'm still not sure about this feature. I think the existing system works well, and I think there's a benefit in just having a single simple way to loop things. |
I'm happy with that too, but if people decide we need something I am in favour of this being it. |
Pretty much every loop I've written recently has looked like this, when more than one nested loop is involved. loop 10 times:
set {_counter} to loop-value
loop {_something::*}:
set {_value} to loop-value-2 It's just so much easier to keep track of what's what, helps avoid off-by-one errors in the loop-value-x, and being able to have descriptive names makes the code way more legible. That said, this code is perfectly fine to keep, but I feel like this addition would be valuable in that it would remove the dead weight of those set lines. |
I have a vague memory that there are some cases where you can't use the |
Yes, any section that resets the events (EffSecSpawn, for example) means you have to put the loop-value into a var in order to access it in the section, since when it runs isn't guaranteed. |
We voted for Sovde's suggestion to go with this version but allow |
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
Skript.registerSection(SecFor.class, | ||
"(for [each]|loop) [value] %~object% in %objects%", | ||
"(for [each]|loop) (key|index) %~object% in %objects%", | ||
"(for [each]|loop) [key|index] %~object% (=|and) [value] %~object% in %objects%" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this =
syntax. Is there a reason you chose it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was either from one of the issues/discussions suggesting this or I was copying from some other language, It's been about six months and I can't really remember.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I remember, I think there was a worry about {x} and {y}
being confusingly-ambiguous (not in terms of parsing but for a user to read, maybe thinking it was looping two items at a time) between a regular list of expressions and this specific syntax where the and
is literally part of it, and we wanted a less-ambiguous alternative that emphasised the keys were mapped to the values.
I'd rather it wasn't a symbol (=) although I don't mind it, but I couldn't think of a better single word for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should avoid symbols if possible. I don't think for each {_a} = {_b} in {_c::*}
is great.
In fact, we might want to require the usage of the keywords key|index
and value
for this option. for each {_a} and {_b} in {_c::*}
makes it seem like c
is holding some sort of tuple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with getting rid of =, how would you feel about ,
as an alternative? Python has e.g. for key, value in dict.items()
and that's not terrible IMO.
I'm just worried that writing out the whole for key {blah} and value {blah} in ...
is going to be more verbose than is necessary, when really we just need tome way to indicate one is the index representing the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would certainly be a better shorthand than =
. I am okay with it, though I dont think for {_key} and {_value} in ...
is too bad
Skript.registerSection(SecFor.class, | ||
"(for [each]|loop) [value] %~object% in %objects%", | ||
"(for [each]|loop) (key|index) %~object% in %objects%", | ||
"(for [each]|loop) [key|index] %~object% (=|and) [value] %~object% in %objects%" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was either from one of the issues/discussions suggesting this or I was copying from some other language, It's been about six months and I can't really remember.
Co-authored-by: Patrick Miller <apickledwalrus@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the implementation is solid. My only concern is with the syntax.
Skript.registerSection(SecFor.class, | ||
"(for [each]|loop) [value] %~object% in %objects%", | ||
"(for [each]|loop) (key|index) %~object% in %objects%", | ||
"(for [each]|loop) [key|index] %~object% (=|and) [value] %~object% in %objects%" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should avoid symbols if possible. I don't think for each {_a} = {_b} in {_c::*}
is great.
In fact, we might want to require the usage of the keywords key|index
and value
for this option. for each {_a} and {_b} in {_c::*}
makes it seem like c
is holding some sort of tuple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation looks fine. My only concern is the syntax (see my existing comments)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work
return walk(event, true); | ||
} | ||
} | ||
|
||
protected void store(Event event, Object next) { | ||
this.current.put(event, next); | ||
this.currentLoopCounter.put(event, (currentLoopCounter.getOrDefault(event, 0L)) + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.currentLoopCounter.put(event, (currentLoopCounter.getOrDefault(event, 0L)) + 1); | |
this.currentLoopCounter.put(event, currentLoopCounter.getOrDefault(event, 0L) + 1); |
The parentheses use seems a bit odd here
Skript.error("The 'key' input for a for-loop must be a variable to store the value."); | ||
return false; | ||
} | ||
if (!(valueStore instanceof Variable || valueStore == null)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!(valueStore instanceof Variable || valueStore == null)) { | |
if (valueStore != null && !(valueStore instanceof Variable)) { |
Just to bring it in line with the keyStore
check (and I think this is clearer)
} | ||
if (Container.class.isAssignableFrom(expression.getReturnType())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
if (Container.class.isAssignableFrom(expression.getReturnType())) { | |
} | |
if (Container.class.isAssignableFrom(expression.getReturnType())) { |
} | ||
if (!LiteralUtils.canInitSafely(expression)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
if (!LiteralUtils.canInitSafely(expression)) { | |
} | |
if (!LiteralUtils.canInitSafely(expression)) { |
} | ||
if (!(valueStore instanceof Variable || valueStore == null)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
if (!(valueStore instanceof Variable || valueStore == null)) { | |
} | |
if (!(valueStore instanceof Variable || valueStore == null)) { |
return false; | ||
//<editor-fold desc="Set the key/value expressions based on the pattern" defaultstate="collapsed"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return false; | |
//<editor-fold desc="Set the key/value expressions based on the pattern" defaultstate="collapsed"> | |
return false; | |
//<editor-fold desc="Set the key/value expressions based on the pattern" defaultstate="collapsed"> |
Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com>
Description
Having talked with Ayham about my concerns, I've opened this as an alternative proposal to Ayham's loop PR #6053.
This will be in draft until we reach a consensus about which approach to adopt.
Ayham's syntax was:
I'm not very happy about changing or adding to the existing
loop ...
section syntax, because it's such an old and established thing, and I worried that the syntax was becoming a bit long and difficult to interpret.I also thought this feature might be a good opportunity to mimic for-each loops from other languages like Java and Python.
My alternative for-each is specifically designed for dealing with key<->value maps,
by storing the index and value in reference variables.
It also extends the existing
SecLoop
so all loop behaviour is available as normal.The syntax is (note ~object specifically accepts a variable):
Note: while I wanted to do
for A, B in ...
(like Python) I was concerned that Skript might mistake this forfor <list of A, B> in ...
rather thanfor <A>, <B> in ...
.Note: this is registered as an experimental feature, toggled with
using for each loops
.Target Minecraft Versions: any
Requirements: #6551, #6552
Related Issues: #6052, #6053