Thread overview
Static arrays and std.algorithm.sort
Feb 20, 2014
D Apprentice
Feb 20, 2014
Stanislav Blinov
Feb 20, 2014
D Apprentice
Feb 20, 2014
Stanislav Blinov
Feb 20, 2014
Stanislav Blinov
Feb 21, 2014
Jesse Phillips
Feb 20, 2014
Meta
Feb 21, 2014
John Colvin
February 20, 2014
Greetings, D wizards.

Given a static array, int[5] a, presumed to be filled with random
numbers, how does one sort it using std.algorithm.sort? Calling
sort(a) by itself errors out with:

test.d(7): Error: template std.algorithm.sort does not match any
function template declaration. Candidates are:
/usr/share/dmd/src/phobos/std/algorithm.d(8387):
std.algorithm.sort(alias less = "a < b", SwapStrategy ss =
SwapStrategy.unstable, Range)(Range r) if ((ss ==
SwapStrategy.unstable && (hasSwappableElements!Range ||
hasAssignableElements!Range) || ss != SwapStrategy.unstable &&
hasAssignableElements!Range) && isRandomAccessRange!Range &&
hasSlicing!Range && hasLength!Range)
test.d(7): Error: template std.algorithm.sort(alias less = "a <
b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) if
((ss == SwapStrategy.unstable && (hasSwappableElements!Range ||
hasAssignableElements!Range) || ss != SwapStrategy.unstable &&
hasAssignableElements!Range) && isRandomAccessRange!Range &&
hasSlicing!Range && hasLength!Range) cannot deduce template
function from argument types !()(int[5])

This is a general interest question. As I understand it, D static
arrays are value types, as opposed to their dynamic siblings
which are reference types, and I suspect that is the underlying
issue here.

One little idiom I found, though I do not know if it's very
efficient, is using the array slice syntax:

sort (a[0..a.length]);

This works, but I'm curious if there's another (better) way? The
biggest advantage that I can see to the slice syntax is that it
allows the programmer to sort only part of the array, which one
could do in C with qsort.

Source:

import std.stdio;
import std.algorithm;

void main ()
{
	int[5] a = [9, 5, 1, 7, 3];
	//sort (a); //Fails
	//sort (a[0..a.length]); //Works
	writeln (a);
}

Thank you for your time.
February 20, 2014
On Thursday, 20 February 2014 at 17:24:55 UTC, D Apprentice wrote:

> This works, but I'm curious if there's another (better) way?

sort(a[]);
February 20, 2014
On Thursday, 20 February 2014 at 17:29:44 UTC, Stanislav Blinov
wrote:
> On Thursday, 20 February 2014 at 17:24:55 UTC, D Apprentice wrote:
>
>> This works, but I'm curious if there's another (better) way?
>
> sort(a[]);

That's still using the slice syntax though? I just reread the
documentation and it says that slicing does not copy any data, so
there shouldn't be any issues with this method.

But I'm curious, are there any other known ways, or is
this the only one?

Thank you for your reply.
February 20, 2014
On Thursday, 20 February 2014 at 17:34:37 UTC, D Apprentice wrote:
> On Thursday, 20 February 2014 at 17:29:44 UTC, Stanislav Blinov
> wrote:

>> sort(a[]);
>
> That's still using the slice syntax though? I just reread the
> documentation and it says that slicing does not copy any data, so
> there shouldn't be any issues with this method.

Yup.

> But I'm curious, are there any other known ways, or is
> this the only one?

No. To be honest, I'm not fully agreeing with sort(a) not working too, but it seems unlikely it'd be supported.

See http://d.puremagic.com/issues/show_bug.cgi?id=4114
February 20, 2014
I believe the problem is that std.algorithm.sort requires a
range, and fixed-size arrays are not ranges in D. I believe it's
because the most basic range functionality is the ability to do
this:

int[] arr = [0, 1, 2, 3];
while (arr.length > 0)
{
     arr = arr[1..arr.length];
}

In other words, shrink the range size, which is obviously not
possible with a fixed-size array, since its size is... fixed. The
reason your example code works:

void main ()
{
	int[5] a = [9, 5, 1, 7, 3];
	//sort (a); //Fails
         //Note that `a[0..a.length]` is equivalent to the shorter
syntax `a[]`
	//sort (a[0..a.length]); //Works
	writeln (a);
}

Is because while int[5] is not a range, int[] *is* a range, as I
demonstrated above. Although int[5] is not a range, you can
obtain a range "view" of it with the square brackets syntax. This
is referred to as slicing. The following are all valid slices of
an int[5]:

int[5] arr = [0, 1, 2, 3];
auto slice1 = arr[0..$]; //$ means arr.length in this context.
                          //slice1 == [0, 1, 2, 3]

auto slice2 = arr[1..$]; //slice2 == [1, 2, 3]

auto slice3 = arr[1..3]; //slice3 == [1, 2]

auto slice4 = arr[0..0]; //slice4 == [] empty slice, length == 0
but ptr != null
February 20, 2014
Note that you can create your own overload. Though it has to be done "the long way", because dmd doesn't (yet?) allow overloading templates imported from other modules:

import std.stdio;
import std.algorithm;
import std.traits;

template sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable)
{
    auto sort(Arr)(ref Arr arr) if (isStaticArray!Arr) {
        return std.algorithm.sort!(less, ss)(arr[]);
    }

    auto sort(Range)(Range r) if (!isStaticArray!Range) {
        return std.algorithm.sort!(less, ss)(r);
    }
}

void main ()
{
    int[5] a = [ 9, 5, 1, 7, 3 ];
    int[]  b = [ 4, 2, 1, 6, 3 ];

    sort(a);
    sort(b);
    writeln(a);
    writeln(b);
}
February 21, 2014
On Thursday, 20 February 2014 at 18:33:02 UTC, Stanislav Blinov wrote:
> Note that you can create your own overload. Though it has to be done "the long way", because dmd doesn't (yet?) allow overloading templates imported from other modules:

Guess we will find out:
https://d.puremagic.com/issues/show_bug.cgi?id=12216
February 21, 2014
On Thursday, 20 February 2014 at 17:24:55 UTC, D Apprentice wrote:
> Greetings, D wizards.
>
> Given a static array, int[5] a, presumed to be filled with random
> numbers, how does one sort it using std.algorithm.sort? Calling
> sort(a) by itself errors out with:
>
> test.d(7): Error: template std.algorithm.sort does not match any
> function template declaration. Candidates are:
> /usr/share/dmd/src/phobos/std/algorithm.d(8387):
> std.algorithm.sort(alias less = "a < b", SwapStrategy ss =
> SwapStrategy.unstable, Range)(Range r) if ((ss ==
> SwapStrategy.unstable && (hasSwappableElements!Range ||
> hasAssignableElements!Range) || ss != SwapStrategy.unstable &&
> hasAssignableElements!Range) && isRandomAccessRange!Range &&
> hasSlicing!Range && hasLength!Range)
> test.d(7): Error: template std.algorithm.sort(alias less = "a <
> b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) if
> ((ss == SwapStrategy.unstable && (hasSwappableElements!Range ||
> hasAssignableElements!Range) || ss != SwapStrategy.unstable &&
> hasAssignableElements!Range) && isRandomAccessRange!Range &&
> hasSlicing!Range && hasLength!Range) cannot deduce template
> function from argument types !()(int[5])
>
> This is a general interest question. As I understand it, D static
> arrays are value types, as opposed to their dynamic siblings
> which are reference types, and I suspect that is the underlying
> issue here.
>
> One little idiom I found, though I do not know if it's very
> efficient, is using the array slice syntax:
>
> sort (a[0..a.length]);
>
> This works, but I'm curious if there's another (better) way? The
> biggest advantage that I can see to the slice syntax is that it
> allows the programmer to sort only part of the array, which one
> could do in C with qsort.
>
> Source:
>
> import std.stdio;
> import std.algorithm;
>
> void main ()
> {
> 	int[5] a = [9, 5, 1, 7, 3];
> 	//sort (a); //Fails
> 	//sort (a[0..a.length]); //Works
> 	writeln (a);
> }
>
> Thank you for your time.

static arrays are not slices. Using [] gives you a slice from a static array. I often find myself writing this:

int[5] aStatic = [9, 5, 1, 7, 3];
auto a = aStatic[];

and just being careful not to leak references.