Request: a more logical static array behavior

Tommi tommitissari at hotmail.com
Wed Aug 14 17:57:25 PDT 2013


Disclaimer: I'm going to be excruciatingly explicit here just so 
that everybody can follow my train of thought.

References:
1) Subtype/Supertype: http://en.wikipedia.org/wiki/Subtyping

2) Type deduction: 
http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-/Stephan-T-Lavavej-Core-C-2-of-n

3) Range: http://dlang.org/phobos/std_range.html#isInputRange

-------
e.g. = "for example"

Static array, e.g. int[3], is not a range.
Dynamic array, e.g. int[], is a range.

int[] is not a supertype of int[3].

Non-subtype type: "type that is not a subtype of any other type"

Static array types are somewhat magical in D; they can do 
something that no other non-subtype type can do: static arrays 
can implicitly convert to another type during type deduction. 
More specifically, e.g. int[3] can implicitly convert to int[] 
during type deduction.

Here's an example of this:

module test;

enum Ret { static_array, dynamic_array, input_range }

Ret foo(T)(T[3] sa) // [1]
if (is(T == uint))
{
     return Ret.static_array;
}

Ret foo(T)(T[] da) // [2]
{
     return Ret.dynamic_array;
}

enum uint[3] saUints = [0, 0, 0];
enum char[3] saChars = [0, 0, 0];
static assert(foo(saUints) == Ret.static_array);  // [3]
static assert(foo(saChars) == Ret.dynamic_array); // [4]

-------
[3]: A perfect match is found in the first overload of 'foo' [1] 
when its template type parameter 'T' is deduced to be an int. 
Then, the type of the function parameter 'sa' is exactly the same 
as the type of the argument 'saUints'.

[4]: No perfect match is found. But, because 'saChars' is a 
static array, the compiler gives all 'foo' overloads the benefit 
of the doubt, and also checks if a perfect match could be found 
if 'saChars' were first converted to a dynamic array, int[] that 
is. Then, a perfect match is found for int[] in the second 
overload of 'foo' [2] when 'T' is deduced to be an int.

Now, let's add to the previous example:

import std.range;

Ret bar(T)(T[3] sa) // [5]
if (is(T == uint))
{
     return Ret.static_array;
}

Ret bar(R)(R r) // [6]
if (std.range.isInputRange!R)
{
     return Ret.input_range;
}

static assert(bar(saUints) == Ret.static_array); // [7]
static assert(bar(saChars) == Ret.input_range);  // [8]

-------
[7]: This is effectively the same as [3]
[8]: This line throws a compile-time error: "template test.bar 
does not match any function template declaration". Compare this 
to [4]: for some reason, the compiler doesn't give the second 
overload of 'bar' [6] the benefit of the doubt and check to see 
if the call to 'bar' could be made if 'saChars' were first 
converted to int[]. Were the compiler to consider this implicit 
conversion as it does in [4], then it would see that the second 
overload of 'bar' [6] could in fact be called, and the code would 
compile.

Thus, my point is this:
Shouldn't this magical property of static arrays (implicitly 
converting to dynamic array during type deduction) extend to all 
type deduction situations?

I think this would be a breaking change.


NOTE:
Subtypes can implicitly convert to their supertype during type 
deduction, there's nothing magical about that.


More information about the Digitalmars-d mailing list