www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - std.algorithm sort() and reverse() confusion

reply "Paul" <paul example.com> writes:
Given that myVals is a dynamic array of ints...

writeln("Array contents: ", myVals);
writeln("Sorted: ", sort(myVals));
writeln("Sorted, reversed: ", reverse(myVals));

Gives me...

Error: template std.stdio.writeln cannot deduce function from 
argument types !()(string, void)

But, if I bring the reverse out of the call to writeln() it works 
as expected:

writeln("Array contents: ", myVals);
writeln("Sorted: ", sort(myVals));
reverse(myVals);
writeln("Sorted, reversed: ", myVals);

Can someone give me a simple explanation as to why this is so? I 
guess it might be because reverse is 'in place' and the target is 
undefined at compile time but surely that would still be the case 
in the second instance. Somehow it doesn't seem logical to a noob 
like me.
Jan 30 2015
next sibling parent reply "Kagamin" <spam here.lot> writes:
writeln("Sorted, reversed: ", retro(sort(myVals)));
?
Jan 30 2015
parent reply "Paul" <paul example.com> writes:
On Friday, 30 January 2015 at 16:21:24 UTC, Kagamin wrote:
 writeln("Sorted, reversed: ", retro(sort(myVals)));
 ?
Or... writeln("Reverse sorted: ", sort!("a > b")(vals)); but I still don't understand the original 'error'.
Jan 30 2015
parent "Tobias Pankrath" <tobias pankrath.net> writes:
On Friday, 30 January 2015 at 17:07:17 UTC, Paul wrote:
 On Friday, 30 January 2015 at 16:21:24 UTC, Kagamin wrote:
 writeln("Sorted, reversed: ", retro(sort(myVals)));
 ?
Or... writeln("Reverse sorted: ", sort!("a > b")(vals)); but I still don't understand the original 'error'.
Take a look at the return type of reverse.
Jan 30 2015
prev sibling parent reply FG <home fgda.pl> writes:
On 2015-01-30 at 17:07, Paul wrote:
 writeln("Sorted, reversed: ", reverse(myVals));

 Gives me...

 Error: template std.stdio.writeln cannot deduce function from argument types
!()(string, void)
As it should, because reverse returns nothing, void. But you may wonder what the design choice behind that was that reverse doesn't return the range itself while sort does (a SortedRange, specifically).
Jan 30 2015
next sibling parent FG <home fgda.pl> writes:
On 2015-01-30 at 18:42, FG wrote:
 But you may wonder what the design choice behind that was that reverse doesn't
return the range itself while sort does (a SortedRange, specifically).
Although, after thinking about it, it makes sense. sort is used mostly to enforce that something is sorted in case it isn't already, so chaining it with other functions is reasonable, while in case of reverse you don't normally call it very often, it's cheaper to wrap the range in a retro range and iterate backwards when required, without touching the original.
Jan 30 2015
prev sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Friday, January 30, 2015 18:42:57 FG via Digitalmars-d-learn wrote:
 On 2015-01-30 at 17:07, Paul wrote:
 writeln("Sorted, reversed: ", reverse(myVals));

 Gives me...

 Error: template std.stdio.writeln cannot deduce function from argument types
!()(string, void)
As it should, because reverse returns nothing, void. But you may wonder what the design choice behind that was that reverse doesn't return the range itself while sort does (a SortedRange, specifically).
sort returns a different type rather than the original type, and that type indicates that its sorted, and some algoritms are able to take advantage of that. No algorithm is going to care that the data was reversed at some point, so there's no benefit it returning a new range type from reverse. And it's arguably better that a function that mutates something in place does not return it - especially with ranges - because that very easily gives the impression that the original is not mutated (since most range-based functions don't alter their arguments - they just wrap them in a new range type or return a portion of the original range). Regardless, I think that the difference between sort and reverse comes down to the fact that there's a definite benefit in returning a new type from sort, whereas there is no such benefit with reverse, so there's no need to return anything. So, whether it _should_ return anything is then a very different question than it is with sort. - Jonathan M Davis
Jan 30 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/30/2015 09:55 AM, Jonathan M Davis via Digitalmars-d-learn wrote:

 sort returns a different type rather than the original type, and that 
type
 indicates that its sorted, and some algoritms are able to take 
advantage of
 that.
I covered that a little bit during DConf 2014, at around 4:30 minute mark here: http://www.youtube.com/watch?x-yt-cl=85114404&v=oF8K4-bieaw&feature=player_detailpage&x-yt-ts=1422579428#t=267
 there is no such benefit with reverse, so there's no need to
 return anything.
Still, returning the original range would help with chaining calls: arr.reverse.map!sqrt Side note: There is the confusion between the .reverse property of arrays and std.algorithm.reverse. :-/ Ali
Jan 30 2015
next sibling parent "Paul" <paul example.com> writes:
On Friday, 30 January 2015 at 18:46:55 UTC, Ali Çehreli wrote:
 there is no such benefit with reverse, so there's no need to
 return anything.
Still, returning the original range would help with chaining calls: arr.reverse.map!sqrt Side note: There is the confusion between the .reverse property of arrays and std.algorithm.reverse. :-/ Ali
Thanks all, I now understand why this happens, although as a newcomer, it seems a little odd that these 'utility functions' have to be handled differently. Paul
Jan 30 2015
prev sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Friday, January 30, 2015 10:46:54 Ali Çehreli via Digitalmars-d-learn wrote:
 On 01/30/2015 09:55 AM, Jonathan M Davis via Digitalmars-d-learn wrote:
  > there is no such benefit with reverse, so there's no need to
  > return anything.

 Still, returning the original range would help with chaining calls:

    arr.reverse.map!sqrt
Yes, but arguably, chaining calls in this case is bad, because normally when you're chaining calls with range-based functions, you're not mutating the original range, whereas with reverse, you are. So, it could easily give the impression that it's doing what retro does rather than reversing the elements in place. - Jonathan M Davis
Jan 30 2015
parent "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

    arr.reverse.map!sqrt
Yes, but arguably, chaining calls in this case is bad,
We have discussed this some time... and I'd like reverse() to return the original array (like the deprecated array .reverse property). It's not a perfect design, but allowing UFCS chains is quite important. Bye, bearophile
Feb 02 2015