www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - .sort vs sort(): std.algorithm not up to the task?

reply Andrew Edwards <edwards.ac gmail.com> writes:
Ranges may be finite or infinite but, while the destination may 
be unreachable, we can definitely tell how far we've traveled. So 
why doesn't this work?

import std.traits;
import std.range;

void main()
{
     string[string] aa;

     // what others have referred to as
     // standard sort works but is deprecated
     //auto keys = aa.keys.sort;

     // Error: cannot infer argument types, expected 1 argument, 
not 2
     import std.algorithm: sort;
     auto keys = aa.keys.sort();

     // this works but why should I have to?
     //import std.array: array;
     //auto keys = aa.keys.sort().array;

     foreach (i, v; keys){}
}

If I hand you a chihuahua for grooming, why am I getting back a 
pit bull? I simply want a groomed chihuahua. Why do I need to 
consult a wizard to get back a groomed chihuahua?
Jun 07 2017
next sibling parent reply Mike B Johnson <Mikey Ikes.com> writes:
On Thursday, 8 June 2017 at 01:57:47 UTC, Andrew Edwards wrote:
 If I hand you a chihuahua for grooming, why am I getting back a 
 pit bull? I simply want a groomed chihuahua. Why do I need to 
 consult a wizard to get back a groomed chihuahua?
Because is like a poodle and unless you get your hair cut in a special way you won't be considered for the job! The wizard only exists to balance the symmetric arrangement of the interplanetary forces, don't fear him, he does his job in a very predictable way.
Jun 07 2017
parent reply Andrew Edwards <edwards.ac gmail.com> writes:
On Thursday, 8 June 2017 at 02:07:07 UTC, Mike B Johnson wrote:
 On Thursday, 8 June 2017 at 01:57:47 UTC, Andrew Edwards wrote:
 If I hand you a chihuahua for grooming, why am I getting back 
 a pit bull? I simply want a groomed chihuahua. Why do I need 
 to consult a wizard to get back a groomed chihuahua?
Because is like a poodle and unless you get your hair cut in a special way you won't be considered for the job! The wizard only exists to balance the symmetric arrangement of the interplanetary forces, don't fear him, he does his job in a very predictable way.
Pretty funny. But seriously, this is something that just work. There is now to layers of indirection to achieve what I used to do quite naturally in the language.
Jun 07 2017
next sibling parent Andrew Edwards <edwards.ac gmail.com> writes:
On Thursday, 8 June 2017 at 02:19:15 UTC, Andrew Edwards wrote:
 Pretty funny. But seriously, this is something that just work. 
 There is now to layers of indirection to achieve what I used to 
 do quite naturally in the language.
*should just work
Jun 07 2017
prev sibling parent Era Scarecrow <rtcvb32 yahoo.com> writes:
On Thursday, 8 June 2017 at 02:19:15 UTC, Andrew Edwards wrote:
 Pretty funny. But seriously, this is something that should just 
 work. There is now to layers of indirection to achieve what I 
 used to do quite naturally in the language.
Hmmm while working on my recent sudoku solver using pointers to structs, i had opCmp defined, but it was still sorting by pointer address rather than how i told it to sort; I had to give it the hint of sort!"*a < *b" for it to work right. It does seem like a little more duct-tape on the wizard is needed in some cases. Thankfully it isn't too complex to know where to tape the wand into the wizard's hand.
Jun 07 2017
prev sibling next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 8 June 2017 at 01:57:47 UTC, Andrew Edwards wrote:
 Ranges may be finite or infinite but, while the destination may 
 be unreachable, we can definitely tell how far we've traveled. 
 So why doesn't this work?

 import std.traits;
 import std.range;

 void main()
 {
     string[string] aa;

     // what others have referred to as
     // standard sort works but is deprecated
     //auto keys = aa.keys.sort;

     // Error: cannot infer argument types, expected 1 argument, 
 not 2
     import std.algorithm: sort;
     auto keys = aa.keys.sort();

     // this works but why should I have to?
     //import std.array: array;
     //auto keys = aa.keys.sort().array;

     foreach (i, v; keys){}
 }

 If I hand you a chihuahua for grooming, why am I getting back a 
 pit bull? I simply want a groomed chihuahua. Why do I need to 
 consult a wizard to get back a groomed chihuahua?
aa.keys.sort() should just work as is: aa.keys returns a string[], and that's a random access range that can be sorted. What exactly is the error?
Jun 07 2017
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Thursday, 8 June 2017 at 02:21:03 UTC, Stanislav Blinov wrote:
 aa.keys.sort() should just work as is: aa.keys returns a 
 string[], and that's a random access range that can be sorted. 
 What exactly is the error?
It does not ... I provided the code and related error message. See the line right above "import std.algorith: sort;".
Jun 07 2017
prev sibling next sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, June 08, 2017 01:57:47 Andrew Edwards via Digitalmars-d-learn 
wrote:
 Ranges may be finite or infinite but, while the destination may
 be unreachable, we can definitely tell how far we've traveled. So
 why doesn't this work?

 import std.traits;
 import std.range;

 void main()
 {
      string[string] aa;

      // what others have referred to as
      // standard sort works but is deprecated
      //auto keys = aa.keys.sort;

      // Error: cannot infer argument types, expected 1 argument,
 not 2
      import std.algorithm: sort;
      auto keys = aa.keys.sort();

      // this works but why should I have to?
      //import std.array: array;
      //auto keys = aa.keys.sort().array;

      foreach (i, v; keys){}
 }
Ranges do not support iterating with an index. The workaround if you want to have an index with ranges and foreach, then you should use lockstep: http://dlang.org/phobos/std_range.html#lockstep e.g. foreach(i, v; lockstep(iota!size_t(0), s)) {} or foreach(i, v; lockstep(iota(0), s)) {} if you don't mind i being an int instead of a size_t. Now, with your example, there are two other solutions that are even easier. sort() sorts the range that it's given in place but returns a wrapper range so that other algorithms can recognize the range as sorted. So, if you did auto keys = aa.keys; sort(keys); foreach(i; v) {} then it will work just fine, because you're still dealing with an array. Alternatively, you could use SortedRange's release function to get the array out of the SortedRange (though note if you do that, you shouldn't then use the SortedRange anymore, since it does a move call to actual move the wrapped range out of the SortedRange). e.g. auto keys = aa.keys.sort().release(); foreach(i; v) {} and that would allow you to still do it in one line. - Jonathan M Davis
Jun 07 2017
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 8 June 2017 at 02:25:17 UTC, Jonathan M Davis wrote:

Oh I see, the was error related to iteration, not sorting.

 Ranges do not support iterating with an index. The workaround 
 if you want to have an index with ranges and foreach, then you 
 should use lockstep:

 http://dlang.org/phobos/std_range.html#lockstep

 e.g.

 foreach(i, v; lockstep(iota!size_t(0), s))
 {}

 or

 foreach(i, v; lockstep(iota(0), s))
 {}
There's an enumerate(): https://dlang.org/phobos/std_range.html#enumerate import std.algorithm : sort; import std.range : enumerate; foreach(i, k; aa.keys.sort().enumerate) { /* ... */ }
Jun 07 2017
next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, June 08, 2017 02:31:43 Stanislav Blinov via Digitalmars-d-learn 
wrote:
 On Thursday, 8 June 2017 at 02:25:17 UTC, Jonathan M Davis wrote:

 Oh I see, the was error related to iteration, not sorting.

 Ranges do not support iterating with an index. The workaround
 if you want to have an index with ranges and foreach, then you
 should use lockstep:

 http://dlang.org/phobos/std_range.html#lockstep

 e.g.

 foreach(i, v; lockstep(iota!size_t(0), s))
 {}

 or

 foreach(i, v; lockstep(iota(0), s))
 {}
There's an enumerate(): https://dlang.org/phobos/std_range.html#enumerate import std.algorithm : sort; import std.range : enumerate; foreach(i, k; aa.keys.sort().enumerate) { /* ... */ }
Even better. I hadn't realized that such a function had been added. - Jonathan M Davis
Jun 07 2017
prev sibling next sibling parent reply Andrew Edwards <edwards.ac gmail.com> writes:
On Thursday, 8 June 2017 at 02:31:43 UTC, Stanislav Blinov wrote:
 On Thursday, 8 June 2017 at 02:25:17 UTC, Jonathan M Davis 
 wrote:

 Oh I see, the was error related to iteration, not sorting.

 Ranges do not support iterating with an index. The workaround 
 if you want to have an index with ranges and foreach, then you 
 should use lockstep:

 http://dlang.org/phobos/std_range.html#lockstep

 e.g.

 foreach(i, v; lockstep(iota!size_t(0), s))
 {}

 or

 foreach(i, v; lockstep(iota(0), s))
 {}
There's an enumerate(): https://dlang.org/phobos/std_range.html#enumerate import std.algorithm : sort; import std.range : enumerate; foreach(i, k; aa.keys.sort().enumerate) { /* ... */ }
Note that I already demonstrated the same functionality by importing "std.array: array" to get the job done. Neither lockstep nor enumerate gets me more benefit in this particular situation that array doesn't already get me. My question here is not whether the job can get done or not, it's simply why the extra work? I still have to import two modules, when before I didn't have to import any. I completely understand the differences between ranges and arrays... the thing is, I wasn't working with ranges but arrays instead. If sort understands a string or array as a sort of range, then given one of those entities, it should manipulate it internally and return it in it's original flavor. Given an array, return an array unless specifically told to do otherwise.
Jun 07 2017
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, June 08, 2017 03:15:11 Andrew Edwards via Digitalmars-d-learn 
wrote:
 On Thursday, 8 June 2017 at 02:31:43 UTC, Stanislav Blinov wrote:
 On Thursday, 8 June 2017 at 02:25:17 UTC, Jonathan M Davis
 wrote:

 Oh I see, the was error related to iteration, not sorting.

 Ranges do not support iterating with an index. The workaround
 if you want to have an index with ranges and foreach, then you
 should use lockstep:

 http://dlang.org/phobos/std_range.html#lockstep

 e.g.

 foreach(i, v; lockstep(iota!size_t(0), s))
 {}

 or

 foreach(i, v; lockstep(iota(0), s))
 {}
There's an enumerate(): https://dlang.org/phobos/std_range.html#enumerate import std.algorithm : sort; import std.range : enumerate; foreach(i, k; aa.keys.sort().enumerate) { /* ... */ }
Note that I already demonstrated the same functionality by importing "std.array: array" to get the job done. Neither lockstep nor enumerate gets me more benefit in this particular situation that array doesn't already get me. My question here is not whether the job can get done or not, it's simply why the extra work? I still have to import two modules, when before I didn't have to import any. I completely understand the differences between ranges and arrays... the thing is, I wasn't working with ranges but arrays instead. If sort understands a string or array as a sort of range, then given one of those entities, it should manipulate it internally and return it in it's original flavor. Given an array, return an array unless specifically told to do otherwise.
sort() returns a SortedRange so that other algorithms can know that the range is sorted and take advantage of that. If sort() returned the original range type, it would be detrimental for other algorithms. But you can just use the array directly again after calling sort or call release() on the SortedRange to get the array out of it. - Jonathan M Davis
Jun 07 2017
parent reply Andrew Edwards <edwards.ac gmail.com> writes:
On Thursday, 8 June 2017 at 03:40:08 UTC, Jonathan M Davis wrote:
 On Thursday, June 08, 2017 03:15:11 Andrew Edwards via 
 Digitalmars-d-learn wrote:
 I completely understand the differences between ranges and 
 arrays... the thing is, I wasn't working with ranges but 
 arrays instead. If sort understands a string or array as a 
 sort of range, then given one of those entities, it should 
 manipulate it internally and return it in it's original 
 flavor. Given an array, return an array unless specifically 
 told to do otherwise.
sort() returns a SortedRange so that other algorithms can know that the range is sorted and take advantage of that. If sort() returned the original range type, it would be detrimental for other algorithms. But you can just use the array directly again after calling sort or call release() on the SortedRange to get the array out of it. - Jonathan M Davis
Yes, I understand that. Again, using "std.range: release" earns me nothing more than I already get from "std.array: array" or if you prefer "std.range: array". I can understand if sort returns Range by default but can be instructed to return the original representation. aa.keys.sort!returnOriginalRepresentation; // or something to that effect But it doesn't, it decides what i'm gonna get like it or not. But the fact, a lot of times I just want to work with the underlying data after the operation is performed. And it should be noted that this applies to Ranges in general not just sort.
Jun 07 2017
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 8 June 2017 at 04:07:22 UTC, Andrew Edwards wrote:
 On Thursday, 8 June 2017 at 03:40:08 UTC, Jonathan M Davis
 sort() returns a SortedRange so that other algorithms can 
 know...
Yes, I understand that. Again, using "std.range: release" earns me nothing more than I already get from "std.array: array" or if you prefer "std.range: array".
Earns you nothing? How about not performing an allocation and copy?
 I can understand if sort returns Range by default but can be 
 instructed to return the original representation.
      aa.keys.sort!returnOriginalRepresentation; // or something 
 to that effect
"Something to that effect" is exactly this: aa.keys.sort().release; No need to import anything but std.algorithm : sort.
 But it doesn't, it decides what i'm gonna get like it or not. 
 But the fact, a lot of times I just want to work with the 
 underlying data after the operation is performed. And it should 
 be noted that this applies to Ranges in general not just sort.
A crucial point of any good design is to *not rob the caller of useful information*. sort() follows that philosophy. If you don't need the extra information, you're free to get rid of it. The other way around that you seem to be proposing would require having a ton of overloads for sort() for any imaginable use case.
Jun 07 2017
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Thursday, 8 June 2017 at 04:15:12 UTC, Stanislav Blinov wrote:
 Earns you nothing? How about not performing an allocation and 
 copy?
Seen through the eyes of a complete beginner, this means absolutely nothing. Those are the eyes I am using as I'm reading a book and simply following the instructions provided. I took care of the problem with the first thing that came to mind, because that all that's required.
 aa.keys.sort().release;
somehow, I missed the point that actually came as a byproduct of importing sort. When I tried it in the original code it "ostensibly" did not work because, i recompiled the edited version posed here.
 No need to import anything but std.algorithm : sort.

 But it doesn't, it decides what i'm gonna get like it or not. 
 But the fact, a lot of times I just want to work with the 
 underlying data after the operation is performed. And it 
 should be noted that this applies to Ranges in general not 
 just sort.
A crucial point of any good design is to *not rob the caller of useful information*. sort() follows that philosophy. If you don't need the extra information, you're free to get rid of it. The other way around that you seem to be proposing would require having a ton of overloads for sort() for any imaginable use case.
No I'm not proposing that at all, if the predicate is initialized such that it functions the exact same way it does now, then only in instances where necessary would the user need to specify anything. Anyway, the functionality I'm asking for is the one forded by release so i'm satisfied. Thank you.
Jun 07 2017
prev sibling next sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, June 08, 2017 04:07:22 Andrew Edwards via Digitalmars-d-learn 
wrote:
 On Thursday, 8 June 2017 at 03:40:08 UTC, Jonathan M Davis wrote:
 On Thursday, June 08, 2017 03:15:11 Andrew Edwards via

 Digitalmars-d-learn wrote:
 I completely understand the differences between ranges and
 arrays... the thing is, I wasn't working with ranges but
 arrays instead. If sort understands a string or array as a
 sort of range, then given one of those entities, it should
 manipulate it internally and return it in it's original
 flavor. Given an array, return an array unless specifically
 told to do otherwise.
sort() returns a SortedRange so that other algorithms can know that the range is sorted and take advantage of that. If sort() returned the original range type, it would be detrimental for other algorithms. But you can just use the array directly again after calling sort or call release() on the SortedRange to get the array out of it. - Jonathan M Davis
Yes, I understand that. Again, using "std.range: release" earns me nothing more than I already get from "std.array: array" or if you prefer "std.range: array". I can understand if sort returns Range by default but can be instructed to return the original representation.
release is a member of SortedRange. You don't have to import it separately. You have it automatically by virtue of the fact that sort returns a SortedRange. And unlike calling array, it doesn't copy the entire range or allocate.
       aa.keys.sort!returnOriginalRepresentation; // or something
 to that effect

 But it doesn't, it decides what i'm gonna get like it or not. But
 the fact, a lot of times I just want to work with the underlying
 data after the operation is performed. And it should be noted
 that this applies to Ranges in general not just sort.
It's just life with ranges that you're usually going to end up with a new type when you call a range-based functions. Most of them can't even do what they're supposed to do without returning a new type, and that type often is not same level of range as the original (e.g. filter returns a new range, and it's only a forward range even if the original is a random-access range, and it can't do otherwise given that it's lazy). Pretty much the only way for ranges in general to return the same type would be if you were only dealing with dynamic arrays, and you were willing to have the range-based function not only be non-lazy, but you were also willing to have it allocate. And if you're going that route, you might as well just have functions operating on dynamic arrays instead of ranges. As it stands, we have functions that return lazy ranges so that they're efficient, and if you want a dynamic array back, you call array on the result. Sure, if you're looking to only operate on dynamic arrays, then that can be a bit annoying, but overall, it leads to much more efficient code, and a lot of code works just fine without to call array having to worry about whether dynamic arrays are involved at all. It's true that sort could work with returning the original type and without allocating (unlike a function like filter), but having it return SortedRange is beneficial overall, and calling release to get the original out is as short as passing a template argument like you're suggesting. Also, you can simply call sort on a separate line and continue to use the array without worrying about sort's return value. So, while I can understand that you'd like sort to just return the array in this case, it's so simple to work around it that this really doesn't seem like it should be a big deal. The reality of the matter is that if you're going to be annoyed about range-based functions returning new types, you're going to be annoyed a lot when dealing with range-based functions. - Jonathan M Davis
Jun 08 2017
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Thursday, 8 June 2017 at 07:23:27 UTC, Jonathan M Davis wrote:
 release is a member of SortedRange. You don't have to import it 
 separately. You have it automatically by virtue of the fact 
 that sort returns a SortedRange. And unlike calling array, it 
 doesn't copy the entire range or allocate.
sorry, I missed that after accidentally making the change in on file and compiled another.
 having it return SortedRange is beneficial overall, and calling 
 release to get the original out is as short as passing a 
 template argument like you're suggesting.
a point I missed do to the aforementioned mistake. Thanks for the assist, Andrew
Jun 08 2017
prev sibling parent Russel Winder via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Thu, 2017-06-08 at 00:23 -0700, Jonathan M Davis via Digitalmars-d-
learn wrote:
 [=E2=80=A6]
=20
 release is a member of SortedRange. You don't have to import it
 separately.
 You have it automatically by virtue of the fact that sort returns a
 SortedRange. And unlike calling array, it doesn't copy the entire
 range or
 allocate.
=20
[=E2=80=A6] I will have to admit, that on my recent return to more full time D programming, that using both class members, and imported functions with UFCS, can lead to annoyance of understanding. I can't put my finger on what paragraph of documentation would help just yet though. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Jun 08 2017
prev sibling parent Russel Winder via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Wed, 2017-06-07 at 19:39 -0700, Jonathan M Davis via Digitalmars-d-
learn wrote:
=20
[=E2=80=A6]
 Even better. I hadn't realized that such a function had been added.
=20
Another import from Python. :-) --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Jun 08 2017
prev sibling next sibling parent Seb <seb wilzba.ch> writes:
On Thursday, 8 June 2017 at 01:57:47 UTC, Andrew Edwards wrote:
 Ranges may be finite or infinite but, while the destination may 
 be unreachable, we can definitely tell how far we've traveled. 
 So why doesn't this work?
 ...
 If I hand you a chihuahua for grooming, why am I getting back a 
 pit bull? I simply want a groomed chihuahua. Why do I need to 
 consult a wizard to get back a groomed chihuahua?
A magician should never reveal his secrets, but this I do share. .sort() returns a SortedRange [1] that encapsulates the range. The trick is to use .release() to release the controlled range and return it, e.g. import std.algorithm : sort; auto keys = aa.keys.sort().release; [1] https://dlang.org/phobos/std_range.html#SortedRange
Jun 07 2017
prev sibling next sibling parent 9il <ilyayaroshenko gmail.com> writes:
On Thursday, 8 June 2017 at 01:57:47 UTC, Andrew Edwards wrote:
 Ranges may be finite or infinite but, while the destination may 
 be unreachable, we can definitely tell how far we've traveled. 
 So why doesn't this work?

 import std.traits;
 import std.range;

 void main()
 {
     string[string] aa;

     // what others have referred to as
     // standard sort works but is deprecated
     //auto keys = aa.keys.sort;

     // Error: cannot infer argument types, expected 1 argument, 
 not 2
     import std.algorithm: sort;
     auto keys = aa.keys.sort();

     // this works but why should I have to?
     //import std.array: array;
     //auto keys = aa.keys.sort().array;

     foreach (i, v; keys){}
 }

 If I hand you a chihuahua for grooming, why am I getting back a 
 pit bull? I simply want a groomed chihuahua. Why do I need to 
 consult a wizard to get back a groomed chihuahua?
You may want to slice chihuahua first, pass it to mir.ndslice.sort [1], and get back your groomed sliced chihuahua. [1]
Jun 08 2017
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08.06.2017 03:57, Andrew Edwards wrote:
 Ranges may be finite or infinite but, while the destination may be 
 unreachable, we can definitely tell how far we've traveled. So why 
 doesn't this work?
 
 import std.traits;
 import std.range;
 
 void main()
 {
      string[string] aa;
 
      // what others have referred to as
      // standard sort works but is deprecated
      //auto keys = aa.keys.sort;
 
      // Error: cannot infer argument types, expected 1 argument, not 2
      import std.algorithm: sort;
      auto keys = aa.keys.sort();
 
      // this works but why should I have to?
      //import std.array: array;
      //auto keys = aa.keys.sort().array;
 
      foreach (i, v; keys){}
 }
 
 If I hand you a chihuahua for grooming, why am I getting back a pit 
 bull? I simply want a groomed chihuahua. Why do I need to consult a 
 wizard to get back a groomed chihuahua?
You are not giving away the chihuahua. auto keys = aa.keys; sort(keys); foreach(i,v;keys){}
Jun 08 2017
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/7/17 9:57 PM, Andrew Edwards wrote:
 Ranges may be finite or infinite but, while the destination may be
 unreachable, we can definitely tell how far we've traveled. So why
 doesn't this work?

 import std.traits;
 import std.range;

 void main()
 {
     string[string] aa;

     // what others have referred to as
     // standard sort works but is deprecated
     //auto keys = aa.keys.sort;

     // Error: cannot infer argument types, expected 1 argument, not 2
     import std.algorithm: sort;
     auto keys = aa.keys.sort();

     // this works but why should I have to?
     //import std.array: array;
     //auto keys = aa.keys.sort().array;

     foreach (i, v; keys){}
 }

 If I hand you a chihuahua for grooming, why am I getting back a pit
 bull? I simply want a groomed chihuahua. Why do I need to consult a
 wizard to get back a groomed chihuahua?
The issue here is that arrays are special. Arrays allow foreach(i, v; arr) and foreach(v; arr). Ranges in general do not. So there is no way to forward this capability via the range interface. Not only that, but foreach(i, v; arr) is much different than iterating even a range that returns a tuple in that the index is *specific to the loop* and doesn't involve the array at all. It's more similar to opApply. opApply can help, but still is different than how arrays work (foreach with array is handled directly by the compiler). But ranges are not going to be forwarding this feature just for arrays. In answer to your question, if we returned something that *didn't* take advantage of the fact that the range is now sorted, then people who want that functionality (e.g. builtin binary search) would be complaining. As a recommendation, I suggest you get used to using enumerate, as it will work for all cases of ranges, including arrays. -Steve
Jun 08 2017
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08.06.2017 14:06, Steven Schveighoffer wrote:
 
 The issue here is that arrays are special. Arrays allow foreach(i, v; 
 arr) and foreach(v; arr). Ranges in general do not. So there is no way 
 to forward this capability via the range interface. Not only that, but 
 foreach(i, v; arr) is much different than iterating even a range that 
 returns a tuple in that the index is *specific to the loop* and doesn't 
 involve the array at all. It's more similar to opApply.
 
 opApply can help, but still is different than how arrays work (foreach 
 with array is handled directly by the compiler). But ranges are not 
 going to be forwarding this feature just for arrays.
Arguably, foreach over ranges and foreach over arrays are badly designed. Automatic tuple expansion only works with ranges, and indexed iteration only works with arrays, and they are mutually incompatible. Therefore, there is no good way to fix the problem.
Jun 08 2017