Re: Repost: make foreach(i, a; range) just work

2014-02-25 Thread w0rp
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.


Re: Repost: make foreach(i, a; range) just work

2014-02-25 Thread Regan Heath
On Mon, 24 Feb 2014 17:58:51 -, Jesse Phillips  
jesse.k.phillip...@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/


Re: Repost: make foreach(i, a; range) just work

2014-02-25 Thread Jesse Phillips

On Tuesday, 25 February 2014 at 17:34:25 UTC, Regan Heath wrote:
On Mon, 24 Feb 2014 17:58:51 -, Jesse Phillips 
jesse.k.phillip...@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.


Seems right, though 4 is, to include this behavior would be a 
breaking change, and the polish on this isn't worth it.


Many of your examples use AA and provide examples where their 
iteration has a count variable. I have never wanted to do this, 
and frankly would be extremely concerned for what the code would 
be doing with it. AA are unordered, ranges tend to be ordered, 
but this isn't a requirement.


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 examples you are referring to are specific to the 
foreach you desire, but use enumerate to show the current 
behavior. It was not to claim that your addition would break 
tuple flattening.


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?


Yes, #5 comes down to OMG you'll be able to type lots more text! 
And that is awesome. Who needs this lack of typing.


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.


Ranges aren't always sequential. It doesn't make sense on many 
types of ranges (random, associative array if it provided a 
range). Arrays on the other hand are sequential by definition.


Re: Repost: make foreach(i, a; range) just work

2014-02-24 Thread Regan Heath
On Fri, 21 Feb 2014 19:42:41 -, Jesse Phillips  
jesse.k.phillip...@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/


Re: Repost: make foreach(i, a; range) just work

2014-02-24 Thread Regan Heath
On Fri, 21 Feb 2014 16:59:26 -, Justin Whear  
jus...@economicmodeling.com wrote:



On Fri, 21 Feb 2014 10:02:43 +, Regan Heath wrote:


On Thu, 20 Feb 2014 16:30:42 -, Justin Whear
jus...@economicmodeling.com wrote:


On Thu, 20 Feb 2014 13:04:55 +, 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/


Re: Repost: make foreach(i, a; range) just work

2014-02-24 Thread Jesse Phillips

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.


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread w0rp

On Friday, 21 February 2014 at 02:34:30 UTC, Jesse Phillips wrote:

I don't see enough benefit for making this a language feature.


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.


This.


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Regan Heath
On Thu, 20 Feb 2014 16:30:42 -, Justin Whear  
jus...@economicmodeling.com wrote:



On Thu, 20 Feb 2014 13:04:55 +, 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

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Regan Heath

My current thinking:

 - I still think adding index to range foreach is a good idea.
 - I realise that scheme #2 isn't workable.
 - I still like scheme #1 over tuple expansion as it avoids all the issues  
which make scheme #2 unworkable.

 - enumerate is not as flexible as many people seem to think.


On Fri, 21 Feb 2014 02:34:28 -, Jesse Phillips  
jesse.k.phillip...@gmail.com wrote:



On Thursday, 20 February 2014 at 11:15:14 UTC, Regan Heath wrote:
I am posting this again because I didn't get any feedback on my idea,  
which may be TL;DR or because people think it's a dumb idea and they  
were politely ignoring it :p


I certainly have wanted counts of the range iteration, but I do believe  
it becomes too complex to support and that even if we state 'i' is to  
represent a count and not an index, people will still want an index and  
expect it to be an index of their original range even though it makes no  
possible sense from the perspective of iterating over a different range  
from the original.


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.



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.


My specific example didn't want an index, or rather it wanted an index  
into the result set which I believe is just as common if not more common  
than wanting an index into the source - especially given that they are  
often the same thing.


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.




Scheme 1)


As Marc said, ails backwards-compatibility. A change like this will  
never exist if it isn't backwards compatible. There are very few changes  
which will be accepted if backwards compatibility isn't preserved.


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.




Scheme 2)
However, if a type is given and the type can be unambiguously matched  
to a single tuple component then do so.


double[string] AA;
foreach (string k; AA) {} // k is key


While probably not common, what if one needed to switch key/value

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?



foreach (i, k, v; AA.byPairs.enumerate) {}
foreach (i, k, v; AA) {} // better


Bringing this back to range iteration:

 foreach(i, v1, v2; tuple(0,1).repeat(10))
 writeln(i, \t,v1, \t,v2);

Later the range gets a new value, the foreach would still compile but be  
wrong:


 foreach(i, v1, v2; tuple(0,1,2).repeat(10))
 writeln(i, \t,v1, \t,v2);

With enumerate, there is an error.

 foreach(i, v1, v2; tuple(0,1,2).repeat(10).enumerate)
 writeln(i, \t, v1, \t, v2);
Error: cannot infer argument types


Sure, this is an issue with having the optional index/count variable,  
which is not something foreach with enumerate allows.  This is another  
reason I prefer scheme #1, you never have this issue no matter what.




 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 don't believe this works today.  My understanding of what is currently  
supported is..


foreach(index, value; array) { }
foreach(value; range) { }// no support for index/count
foreach(key, value; tuple) { }   // no support for index/count

And, my understanding of enumerate is that it simply creates a tuple from  
an index and a range value, taking it from the range foreach case above,  
to the tuple foreach case.


This is not extensible to more than 2 values.  In fact, it's pretty  
limited until we get full built-in tuple expansion support.


To test this understanding I pulled down the source for enumerate and  
coded this up:


import std.stdio;
import std.range;
import std.typecons;

..paste enumerate here.. // line 5

void main()
{

Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Regan Heath
On Fri, 21 Feb 2014 10:02:43 -, Regan Heath re...@netmail.co.nz  
wrote:


On Thu, 20 Feb 2014 16:30:42 -, Justin Whear  
jus...@economicmodeling.com wrote:



On Thu, 20 Feb 2014 13:04:55 +, 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?


Answered this myself.  What is supported is:

foreach(key, value; tuple) { }

But, what is not supported is more than 2 values.

R

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Regan Heath
On Thu, 20 Feb 2014 17:09:31 -, Steven Schveighoffer  
schvei...@yahoo.com wrote:


On Thu, 20 Feb 2014 11:07:32 -0500, Regan Heath re...@netmail.co.nz  
wrote:



Only if the compiler prefers opApply to range methods, does it?


It should. If it doesn't, that is a bug.

The sole purpose of opApply is to interact with foreach. If it is masked  
out, then there is no point for having opApply.


Thanks.

So, if we had this support which I am asking for:

foreach(index, value; range) { }

And, if someone adds opApply to that range, with a different type for the  
first variable then an existing foreach (using index, value) is likely to  
stop compiling due to type problems.


This seems acceptable to me.

There is an outside chance it might keep on compiling, like if 'i' is not  
used in a strongly typed way, i.e. passed to a writefln or similar.  In  
this case we have silently changed behaviour.


Is this acceptable?

R

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Steven Schveighoffer
On Fri, 21 Feb 2014 06:21:39 -0500, Regan Heath re...@netmail.co.nz  
wrote:


On Thu, 20 Feb 2014 17:09:31 -, Steven Schveighoffer  
schvei...@yahoo.com wrote:


On Thu, 20 Feb 2014 11:07:32 -0500, Regan Heath re...@netmail.co.nz  
wrote:



Only if the compiler prefers opApply to range methods, does it?


It should. If it doesn't, that is a bug.

The sole purpose of opApply is to interact with foreach. If it is  
masked out, then there is no point for having opApply.


Thanks.

So, if we had this support which I am asking for:

foreach(index, value; range) { }

And, if someone adds opApply to that range, with a different type for  
the first variable then an existing foreach (using index, value) is  
likely to stop compiling due to type problems.


This seems acceptable to me.


I think any type that does both opApply and range iteration is asking for  
problems :) D has a nasty way of choosing all or nothing for overloads,  
meaning it may decide this is a range or this is opApply, but if you  
have both, it picks one or the other.


I'd rather see it do:

1. can I satisfy this foreach using opApply? If yes, do it.
2. If not, can I satisfy this foreach using range iteration?

This may be how it works, I honestly don't know.

There is an outside chance it might keep on compiling, like if 'i' is  
not used in a strongly typed way, i.e. passed to a writefln or similar.   
In this case we have silently changed behaviour.


Is this acceptable?


Adding opApply is changing the API of the range. If the range does  
something different based on whether you use the range interface or  
opApply, then this is a logic error IMO.


The easiest thing is to just not use opApply and range primitives together  
:) One separation I like to use in my code is that you use opApply on a  
container, but range primitives on a range for that container. And a  
container is not a range.


-Steve


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Regan Heath
On Fri, 21 Feb 2014 14:29:37 -, Steven Schveighoffer  
schvei...@yahoo.com wrote:


On Fri, 21 Feb 2014 06:21:39 -0500, Regan Heath re...@netmail.co.nz  
wrote:


On Thu, 20 Feb 2014 17:09:31 -, Steven Schveighoffer  
schvei...@yahoo.com wrote:


On Thu, 20 Feb 2014 11:07:32 -0500, Regan Heath re...@netmail.co.nz  
wrote:



Only if the compiler prefers opApply to range methods, does it?


It should. If it doesn't, that is a bug.

The sole purpose of opApply is to interact with foreach. If it is  
masked out, then there is no point for having opApply.


Thanks.

So, if we had this support which I am asking for:

foreach(index, value; range) { }

And, if someone adds opApply to that range, with a different type for  
the first variable then an existing foreach (using index, value) is  
likely to stop compiling due to type problems.


This seems acceptable to me.


I think any type that does both opApply and range iteration is asking  
for problems :) D has a nasty way of choosing all or nothing for  
overloads, meaning it may decide this is a range or this is opApply,  
but if you have both, it picks one or the other.


I'd rather see it do:

1. can I satisfy this foreach using opApply? If yes, do it.
2. If not, can I satisfy this foreach using range iteration?

This may be how it works, I honestly don't know.

There is an outside chance it might keep on compiling, like if 'i' is  
not used in a strongly typed way, i.e. passed to a writefln or  
similar.  In this case we have silently changed behaviour.


Is this acceptable?


Adding opApply is changing the API of the range. If the range does  
something different based on whether you use the range interface or  
opApply, then this is a logic error IMO.


The easiest thing is to just not use opApply and range primitives  
together :) One separation I like to use in my code is that you use  
opApply on a container, but range primitives on a range for that  
container. And a container is not a range.


Makes sense to me. :)

R

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Daniel Murphy
Steven Schveighoffer  wrote in message 
news:op.xbmyjnnzeav7ka@stevens-macbook-pro.local...



I'd rather see it do:

1. can I satisfy this foreach using opApply? If yes, do it.
2. If not, can I satisfy this foreach using range iteration?

This may be how it works, I honestly don't know.


It is. 



Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Jesse Phillips

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 -, Jesse Phillips 
jesse.k.phillip...@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.


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Regan Heath
On Fri, 21 Feb 2014 15:35:44 -, Jesse Phillips  
jesse.k.phillip...@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/


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Steven Schveighoffer
On Fri, 21 Feb 2014 09:58:58 -0500, Daniel Murphy  
yebbliesnos...@gmail.com wrote:


Steven Schveighoffer  wrote in message  
news:op.xbmyjnnzeav7ka@stevens-macbook-pro.local...



I'd rather see it do:

1. can I satisfy this foreach using opApply? If yes, do it.
2. If not, can I satisfy this foreach using range iteration?

This may be how it works, I honestly don't know.


It is.


Good, thank you for checking!

-Steve


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Justin Whear
On Fri, 21 Feb 2014 10:02:43 +, Regan Heath wrote:

 On Thu, 20 Feb 2014 16:30:42 -, Justin Whear
 jus...@economicmodeling.com wrote:
 
 On Thu, 20 Feb 2014 13:04:55 +, 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


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Jesse Phillips

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.


Re: Repost: make foreach(i, a; range) just work

2014-02-21 Thread Jesse Phillips

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.


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread Marc Schütz
IMO, any change needs to be both backwards-compatible (i.e., it 
should not only just work, as you phrased, but existing code 
should just keep working), and forward-compatible, so as not to 
obstruct any potential improvements of tuple handling.


Scheme #1 fails backwards-compatibility.

Scheme #2 doesn't, but I feel the matching rules if a type is 
specified are too complicated. Instead, I would suggest just to 
always assign the variables from the right, i.e. you cannot skip 
variables, and if you specify a type, it must match the type of 
the value in this position.


If you really want to skip a tuple member (in order to avoid an 
expensive copy), a special token _ or $ could be introduced, 
as has also been suggested in one the tuple unpacking/pattern 
matching DIPs, IIRC.


As for unpacking a tuple value (or key), an additional pair of 
parentheses can be used, so such a feature would still be 
possible in the future:


foreach(i, k, (a,b,c); ...)

(Scheme #3 seems just too complicated for my taste. It's 
important to be intuitively understandable and predictable.)


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread w0rp
I don't think this is a good idea. Say you have a class with 
range methods and add opApply later. Only the opApply delegate 
receives a type other than size_t for the first argument. Now the 
foreach line infers a differnt type for i and code in the outside 
world will break.


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];
}

Then to get a counter with a range, we could follow Python's 
example and use an enumerate function, which would take an 
existing range and wrap it with a counter, so T maps to 
Tuple!(size_t, T).


foreach(index, value; enumerate(range)) {
}

Which is rewritten to roughly this.

foreach(_bla; enumerate(range)) {
alias index = _bla[0];
alias value = _bla[1];
}

If we follow Python's example again, we could also support this 
nested unpacking.


// Now written with UFCS instead.
foreach(index, (index_again, value); range.enumerate.enumerate) {
}

Which can rewrite to roughly this.

foreach(_bla; range.enumerate.enumerate) {
alias index = _bla[0];
alias index_again = _bla[1][0];
alias value = _bla[1][1];
}

I got off on kind of a tangent there, but there you go.


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread w0rp
I probably didn't do enough job of reading your post because it 
looks like you shared some similar ideas. I'm sorry if my post 
reads a little like that.


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread Regan Heath

On Thu, 20 Feb 2014 12:56:27 -, Marc Schütz schue...@gmx.net wrote:

IMO, any change needs to be both backwards-compatible (i.e., it should  
not only just work, as you phrased, but existing code should just  
keep working), and forward-compatible, so as not to obstruct any  
potential improvements of tuple handling.


Scheme #1 fails backwards-compatibility.


Fair enough.  We can always pack things manually using something like the  
enumerate() method mentioned in the link.


Scheme #2 doesn't, but I feel the matching rules if a type is specified  
are too complicated. Instead, I would suggest just to always assign the  
variables from the right, i.e. you cannot skip variables, and if you  
specify a type, it must match the type of the value in this position.


If you really want to skip a tuple member (in order to avoid an  
expensive copy), a special token _ or $ could be introduced, as has  
also been suggested in one the tuple unpacking/pattern matching DIPs,  
IIRC.


As for unpacking a tuple value (or key), an additional pair of  
parentheses can be used, so such a feature would still be possible in  
the future:


foreach(i, k, (a,b,c); ...)


Cool.

(Scheme #3 seems just too complicated for my taste. It's important to be  
intuitively understandable and predictable.)


Fair enough.

Any comments on the initial solution to my original problem?

R

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread Regan Heath

On Thu, 20 Feb 2014 13:04:55 -, w0rp devw...@gmail.com wrote:


I don't think this is a good idea.


Which part?  The initial solution to my initial problem, or one of the 3  
schemes mentioned?


Say you have a class with range methods and add opApply later. Only the  
opApply delegate receives a type other than size_t for the first  
argument. Now the foreach line infers a differnt type for i and code in  
the outside world will break.


Only if the compiler prefers opApply to range methods, does it?

And, if it prefers range methods then any existing class with opApply  
(with more than 1 variable) that gets range methods will break also,  
because foreach(more than 1 variable; range) does not (currently) work.


More importantly, this gets in the way of behaviour which may be  
desirable later, foreach being able to unpack tuples from ranges.


snip :)

R

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread Justin Whear
On Thu, 20 Feb 2014 13:04:55 +, 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);
}


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread Steven Schveighoffer
On Thu, 20 Feb 2014 11:07:32 -0500, Regan Heath re...@netmail.co.nz  
wrote:



Only if the compiler prefers opApply to range methods, does it?


It should. If it doesn't, that is a bug.

The sole purpose of opApply is to interact with foreach. If it is masked  
out, then there is no point for having opApply.


-Steve


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread w0rp

On Thursday, 20 February 2014 at 16:30:42 UTC, Justin Whear wrote:

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);
}


I did not know that. When did that happen? It didn't appear in
any changelogs and it works when I tried it in 2.064 on my
machine too. 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.


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread Justin Whear
On Thu, 20 Feb 2014 19:34:17 +, w0rp wrote:

 On Thursday, 20 February 2014 at 16:30:42 UTC, Justin Whear wrote:
 
 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);
 }
 
 I did not know that. When did that happen? It didn't appear in any
 changelogs and it works when I tried it in 2.064 on my machine too. 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.

January 24th, 2012: http://forum.dlang.org/thread/
mailman.756.1327362275.16222.digitalmar...@puremagic.com#post-
mailman.757.1327365651.16222.digitalmars-d:40puremagic.com

That said, it is not documented, see this bug: http://d.puremagic.com/
issues/show_bug.cgi?id=7361


Re: Repost: make foreach(i, a; range) just work

2014-02-20 Thread Jesse Phillips

On Thursday, 20 February 2014 at 11:15:14 UTC, Regan Heath wrote:
I am posting this again because I didn't get any feedback on my 
idea, which may be TL;DR or because people think it's a dumb 
idea and they were politely ignoring it :p


I certainly have wanted counts of the range iteration, but I do 
believe it becomes too complex to support and that even if we 
state 'i' is to represent a count and not an index, people will 
still want an index and expect it to be an index of their 
original range even though it makes no possible sense from the 
perspective of iterating over a different range from the original.


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).



Scheme 1)


As Marc said, ails backwards-compatibility. A change like this 
will never exist if it isn't backwards compatible. There are very 
few changes which will be accepted if backwards compatibility 
isn't preserved.



Scheme 2)
However, if a type is given and the type can be unambiguously 
matched to a single tuple component then do so.


double[string] AA;
foreach (string k; AA) {} // k is key


While probably not common, what if one needed to switch key/value

string[double] AA;

or something similar, the type system no longer helps. But again, 
this seems pretty much uneventful.



foreach (i, k, v; AA.byPairs.enumerate) {}
foreach (i, k, v; AA) {} // better


Bringing this back to range iteration:

foreach(i, v1, v2; tuple(0,1).repeat(10))
writeln(i, \t,v1, \t,v2);

Later the range gets a new value, the foreach would still compile 
but be wrong:


foreach(i, v1, v2; tuple(0,1,2).repeat(10))
writeln(i, \t,v1, \t,v2);

With enumerate, there is an error.

foreach(i, v1, v2; tuple(0,1,2).repeat(10).enumerate)
writeln(i, \t, v1, \t, v2);
Error: cannot infer argument types

I don't see enough benefit for making this a language feature.


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.