February 21, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | On Friday, 21 February 2014 at 11:12:54 UTC, Regan Heath wrote: > - enumerate is not as flexible as many people seem to think. Only seeing the enumerate missing the ability to optionally add an index, but if you aren't adding an index you don't need enumerate. > On Fri, 21 Feb 2014 02:34:28 -0000, Jesse Phillips <Jesse.K.Phillips+D@gmail.com> wrote: > I don't understand how this is "complex to support"? It's simple. It's a count, not an index unless the range is indexable. If people are going to expect an index here, they will expect one with enumerate as well - and are going to be equally disappointed. So, they need to be aware of this regardless. You've provided 3 schemes to support this feature. This suggest there are several "right" ways to bring this into the language, while you prefer 1 someone may prefer 3. At least with enumerate one will need to go to the documentation which explains enumerate doesn't provide an index... I haven't actually reviewed the docs. >> I also don't find myself needing to count iterations very often, and I believe when I do, it is because I want to use that count as an index (possibly needing to add to some global count, but I don't need it enough to remember). > > The justification for this change is the same as for enumerate. > > It is common enough to make it important, and when it happens it's frustrating enough that it needs fixing. I disagree. Enumerate is satisfactory (since it isn't in Phobos I can see it as frustrating). > For example, I find myself using an index to control loop behaviour, most often for detecting the first and last iterations than anything else. A counter will let you do that just as well as an index. I wonder if there is a change to the algorithm which would allow you to not need the first/last iteration. I think this is the main reason I don't need a count, I've learned different ways to solve a problem. Which is beneficial since it leads to chaining functions instead of relying on foreach. > Sure. I personally find this idea compelling enough to warrant some breakage, it is simple, powerful and extensible and avoids all the issues of optional indexes with tuple expansion. But, I can see how someone might disagree. Yes, I understand. But D is at a stage in its life when not every little detail can be polished. Believe me, D has other areas which need polishing but can't be. >> string[double] AA; >> >> or something similar, the type system no longer helps. But again, this seems pretty much uneventful. > > Perhaps I wasn't clear, this would work fine: > > string[double] AA; > foreach (string v; AA) {} // v is "value" > foreach (double k; AA) {} // k is "key" > > or am I missing the point you're making? if AA is changed to a double[string], then your value loop iterates on keys and your key loop iterates on values. >> foreach(i, v1, v2; tuple(0,1).repeat(10).enumerate) >> writeln(i, "\t", v1, "\t", v2); >> >> This works today! And once enumerate is part of Phobos it will just need an import std.range to use it. I tested all my claims about enumerate. You need it to import std.traits or else is(Largest(...)) will always be false. |
February 21, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jesse Phillips | On Fri, 21 Feb 2014 15:35:44 -0000, Jesse Phillips <Jesse.K.Phillips+D@gmail.com> wrote: > You've provided 3 schemes to support this feature. This suggest there are several "right" ways to bring this into the language, while you prefer 1 someone may prefer 3. Ignore the 3 schemes they were just me thinking about how what I actually want will affect built in tuple expansion etc. I want just 1 thing to change (at this time), an index added to foreach over ranges so that it matches arrays, e.g. foreach(index, value; range) { } The code change is likely quite literally just adding an int to the foreach handler for ranges, passing it to the foreach body, and incrementing it afterwards. That's it, well, plus the front end code to bind the variable. All I am suggesting is that we take what we currently have: foreach([index, ]value; array) { } foreach(value; range) { } foreach(key, value; tuple) { } and make this possible too: foreach([index, ]value; range) { } >>> string[double] AA; >>> >>> or something similar, the type system no longer helps. But again, this seems pretty much uneventful. >> >> Perhaps I wasn't clear, this would work fine: >> >> string[double] AA; >> foreach (string v; AA) {} // v is "value" >> foreach (double k; AA) {} // k is "key" >> >> or am I missing the point you're making? > > if AA is changed to a double[string], then your value loop iterates on keys and your key loop iterates on values. No, I was actually suggesting a change here, the compiler would use type matching not ordering to assign the variables. So because 'v' is a string, it is bound to the value not the key. >>> foreach(i, v1, v2; tuple(0,1).repeat(10).enumerate) >>> writeln(i, "\t", v1, "\t", v2); >>> >>> This works today! And once enumerate is part of Phobos it will just need an import std.range to use it. > > I tested all my claims about enumerate. You need it to import std.traits or else is(Largest(...)) will always be false. Thanks! Ok, so how is this working? ahh, ok I think I get it. enumerate returns a range, whose values are Tuples of index/value where value is also a tuple so is flattened, and then the whole lot is flattened into the foreach. So, while the range foreach only supports: foreach(value; range) { } value in this case is a flattened tuple of (index, v1, v2, ...) Yes? I had completely forgotten about tuple flattening. I don't think this affects what I actually want to change, we can have: foreach(index, value; range) { } and still flatten tuples into value, you would simply have to provide one extra variable to get an index. Make sense? R -- Using Opera's revolutionary email client: http://www.opera.com/mail/ |
February 21, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | On Fri, 21 Feb 2014 10:02:43 +0000, Regan Heath wrote:
> On Thu, 20 Feb 2014 16:30:42 -0000, Justin Whear <justin@economicmodeling.com> wrote:
>
>> On Thu, 20 Feb 2014 13:04:55 +0000, w0rp wrote:
>>>
>>> More importantly, this gets in the way of behaviour which may be desirable later, foreach being able to unpack tuples from ranges. I would like if it was possible to return Tuple!(A, B) from front() and write foreach(a, b; range) to interate through those thing, unpacking the values with an alias, so this...
>>>
>>> foreach(a, b; range) {
>>> }
>>>
>>> ... could rewrite to roughly this. (There may be a better way.)
>>>
>>> foreach(_someInternalName; range) {
>>> alias a = _someInternalName[0];
>>> alias b = _someInternalName[1];
>>> }
>>
>> Tuple unpacking already works in foreach. This code has compiled since at least 2.063.2:
>>
>> import std.stdio;
>> import std.range;
>> void main(string[] args)
>> {
>> auto tuples = ["a", "b", "c"].zip(iota(0, 3));
>>
>> // unpack the string into `s`, the integer into `i`
>> foreach (s, i; tuples)
>> writeln(s, ", ", i);
>> }
>
> Does this work for more than 2 values? Can the first value be something other than an integer?
>
> R
Yes to both questions. In the following example I use a four element tuple, the first element of which is a string:
import std.stdio;
import std.range;
void main(string[] args)
{
auto tuples = ["a", "b", "c"].zip(iota(0, 3), [1.2, 2.3, 3.4], ['x',
'y', 'z']);
foreach (s, i, f, c; tuples)
writeln(s, ", ", i, ", ", f, ", ", c);
}
Compiles with dmd 2.063.2
|
February 21, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | On Friday, 21 February 2014 at 16:41:00 UTC, Regan Heath wrote: > and make this possible too: > > foreach([index, ]value; range) { } I understand the user interface is simple, but you created 3 statements about how it could be achieved and work/not work with the existing setup. Each have their positives and negatives, it would not make sense to "just choose one" and hope it all works out. >> if AA is changed to a double[string], then your value loop iterates on keys and your key loop iterates on values. > > No, I was actually suggesting a change here, the compiler would use type matching not ordering to assign the variables. So because 'v' is a string, it is bound to the value not the key. And string is the key, double[string] is not the same as string[double]. Also string[string], ambiguous yet common. There are many things to consider when adding a feature, it is not good to ignore what can go wrong. > Thanks! Ok, so how is this working? ahh, ok I think I get it. > enumerate returns a range, whose values are Tuples of index/value where value is also a tuple so is flattened, and then the whole lot is flattened into the foreach. Sounds like you understand it, seams foreach will flatten all tuples. > I don't think this affects what I actually want to change, we can have: > > foreach(index, value; range) { } > > and still flatten tuples into value, you would simply have to provide one extra variable to get an index. > > Make sense? Yes, but I'm saying we don't need it because foreach(index, value; range.enumerate) { } is good enough. Not perfect, but good enough. |
February 22, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to w0rp | On Thursday, 20 February 2014 at 19:34:17 UTC, w0rp wrote:
> I suppose the next step after that would be to
> support nested unpacking, but that would require a change in
> syntax so it would be much more complicated.
You mean this?
void main() {
import std.typecons : tuple;
import std.range : repeat;
foreach(k,v1, v2; tuple(1, tuple(2, 3)).repeat(4))
{}
}
Yeah, that works.
|
February 24, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jesse Phillips | On Fri, 21 Feb 2014 19:42:41 -0000, Jesse Phillips <Jesse.K.Phillips+D@gmail.com> wrote: > On Friday, 21 February 2014 at 16:41:00 UTC, Regan Heath wrote: >> and make this possible too: >> >> foreach([index, ]value; range) { } > > I understand the user interface is simple, but you created 3 statements about how it could be achieved and work/not work with the existing setup. Each have their positives and negatives, it would not make sense to "just choose one" and hope it all works out. > >>> if AA is changed to a double[string], then your value loop iterates on keys and your key loop iterates on values. >> >> No, I was actually suggesting a change here, the compiler would use type matching not ordering to assign the variables. So because 'v' is a string, it is bound to the value not the key. > > And string is the key, double[string] is not the same as string[double]. > > Also string[string], ambiguous yet common. > > There are many things to consider when adding a feature, it is not good to ignore what can go wrong. Yes.. something is not being communicated here. I addressed all this in the OP. >> Thanks! Ok, so how is this working? ahh, ok I think I get it. >> enumerate returns a range, whose values are Tuples of index/value where value is also a tuple so is flattened, and then the whole lot is flattened into the foreach. > > Sounds like you understand it, seams foreach will flatten all tuples. > >> I don't think this affects what I actually want to change, we can have: >> >> foreach(index, value; range) { } >> >> and still flatten tuples into value, you would simply have to provide one extra variable to get an index. >> >> Make sense? > > Yes, but I'm saying we don't need it because > > foreach(index, value; range.enumerate) { } > > is good enough. Not perfect, but good enough. No, not good enough. This should just work, there is no good reason for it not to. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/ |
February 24, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Justin Whear | On Fri, 21 Feb 2014 16:59:26 -0000, Justin Whear <justin@economicmodeling.com> wrote: > On Fri, 21 Feb 2014 10:02:43 +0000, Regan Heath wrote: > >> On Thu, 20 Feb 2014 16:30:42 -0000, Justin Whear >> <justin@economicmodeling.com> wrote: >> >>> On Thu, 20 Feb 2014 13:04:55 +0000, w0rp wrote: >>>> >>>> More importantly, this gets in the way of behaviour which may be >>>> desirable later, foreach being able to unpack tuples from ranges. >>>> I would like if it was possible to return Tuple!(A, B) from front() >>>> and write foreach(a, b; range) to interate through those thing, >>>> unpacking the values with an alias, so this... >>>> >>>> foreach(a, b; range) { >>>> } >>>> >>>> ... could rewrite to roughly this. (There may be a better way.) >>>> >>>> foreach(_someInternalName; range) { >>>> alias a = _someInternalName[0]; >>>> alias b = _someInternalName[1]; >>>> } >>> >>> Tuple unpacking already works in foreach. This code has compiled since >>> at least 2.063.2: >>> >>> import std.stdio; >>> import std.range; >>> void main(string[] args) >>> { >>> auto tuples = ["a", "b", "c"].zip(iota(0, 3)); >>> >>> // unpack the string into `s`, the integer into `i` >>> foreach (s, i; tuples) >>> writeln(s, ", ", i); >>> } >> >> Does this work for more than 2 values? Can the first value be something >> other than an integer? >> >> R > > Yes to both questions. In the following example I use a four element > tuple, the first element of which is a string: > > > import std.stdio; > import std.range; > void main(string[] args) > { > auto tuples = ["a", "b", "c"].zip(iota(0, 3), [1.2, 2.3, 3.4], ['x', > 'y', 'z']); > foreach (s, i, f, c; tuples) > writeln(s, ", ", i, ", ", f, ", ", c); > } > > Compiles with dmd 2.063.2 Thanks. I understand this now, I had forgotten about tuple unpacking/flattening. DMD supports at least 4 distinct types of foreach. The range foreach is the one which I want an index/count added to, and this change will have no effect on the tuple case shown above. It should "just work", and there is no good reason not to make it so. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/ |
February 24, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | On Monday, 24 February 2014 at 10:29:46 UTC, Regan Heath wrote:
> No, not good enough. This should just work, there is no good reason for it not to.
>
> R
I have long since given up believing this should be in the language, I'm satisfied with the reasons I gave for why it is not in the language and why it is not needed to be in the language.
You asked for feedback, I've given mine to you. I'm ok with you disagreeing with that.
|
February 25, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jesse Phillips | On Saturday, 22 February 2014 at 03:51:19 UTC, Jesse Phillips wrote:
> On Thursday, 20 February 2014 at 19:34:17 UTC, w0rp wrote:
>> I suppose the next step after that would be to
>> support nested unpacking, but that would require a change in
>> syntax so it would be much more complicated.
>
> You mean this?
>
> void main() {
> import std.typecons : tuple;
> import std.range : repeat;
> foreach(k,v1, v2; tuple(1, tuple(2, 3)).repeat(4))
> {}
> }
>
> Yeah, that works.
Ah, I didn't realise you could decompose tuples that way.
I suppose this in Python...
l = [((1, 2), (3, 4, 5))]
for (x, y), (a, b, c) in l:
print (x, y, a, b, c)
... kind of becomes this in D.
auto left = tuple(1, 2);
auto right = tuple(3, 4, 5);
auto both = tuple(left, right);
auto l = [both];
// identity map function to trick the array into being just a range.
foreach(x, y, a, b, c; l.map!(x => x)) {
writeln(x, y, a, b, c);
}
Then static typing makes you not worry about which thing comes from which tuple.
|
February 25, 2014 Re: Repost: make foreach(i, a; range) "just work" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jesse Phillips | On Mon, 24 Feb 2014 17:58:51 -0000, Jesse Phillips <Jesse.K.Phillips+D@gmail.com> wrote: > On Monday, 24 February 2014 at 10:29:46 UTC, Regan Heath wrote: >> No, not good enough. This should just work, there is no good reason for it not to. >> >> R > > I have long since given up believing this should be in the language, I'm satisfied with the reasons I gave for why it is not in the language and why it is not needed to be in the language. > > You asked for feedback, I've given mine to you. I'm ok with you disagreeing with that. Sure, no worries. :) I'd just like to list your objections here and respond to them all, in one place, without the distracting issues surrounding the 3 extra schemes I mentioned. Can you please correct me if I miss represent you in any way. 1. Adding 'i' on ranges is not necessarily an index and people will expect an index. 2. You don't need to count iterations very often. 3. Your point about the "range gets a new value and foreach would compile but be wrong" 4. This area of D is not important enough to polish 5. We will have enumerate soon, and won't need it. I think this is every point you made in opposition of the change I want (excluding those in opposition of the 3 additional schemes - which in hindsight I should just have left off) I believe objection #3 is invalid. The foreach in the example given is a flattened tuple foreach, not the range foreach I want to change. Making the change I want will have no effect on the given example. I think the strongest objection here is #1, #2 and #4 are fairly subjective and #5 just seems a little odd to me, why would you "want" to type more rather than less? For my point of view, it seems an obvious lack in D that the range foreach doesn't have the same basic functionality as the array foreach. That's pretty much my whole argument, it should just work in the same way as arrays. But, as you say we're free to disagree here, I was just about to suggest we were at an impasse myself. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/ |
Copyright © 1999-2021 by the D Language Foundation