June 08, 2017
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.
June 08, 2017
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.
June 07, 2017
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

June 08, 2017
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.
June 08, 2017
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.
June 08, 2017
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.
June 08, 2017
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

June 08, 2017
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] http://docs.algorithm.dlang.io/latest/mir_ndslice_sorting.html#.sort.sort
June 08, 2017
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){}
June 08, 2017
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