-
-
Notifications
You must be signed in to change notification settings - Fork 741
Add some static array traits #924
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
According to the language specification and discussions of the past, Ranting aside; shouldn't |
What a shame... Sorry. Fixed. Probably I'm a bit tired... |
@@ -4351,6 +4351,118 @@ unittest | |||
//static assert( isAssociativeArray!EAA); | |||
} | |||
|
|||
|
|||
/** | |||
Get static array dimensions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gets the rank (number of dimensions) of a static array type.
This is an important distinction from the dimensions themselves.
Looks like this is failing the auto tester? |
Why not just call it |
static if(isStaticArray!T) | ||
enum staticArrayDimensions = 1 + staticArrayDimensions!(ArrayElementType!T); | ||
else | ||
enum staticArrayDimensions = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a certain amount of precedent in std.traits
for raising an error instead of returning arbitrary sentinel values for invalid input. In particular, the traits that reflect on functions will generally error if the input isn't a function. I think that behaviour would be more useful here than this 0
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO it will just force generic code writers to add more branches in their (already complicated and full of templates) code for essentially same cases: int[1]
and int
.
Consider e.g. this function and its examples: unstd.multidimensionalarray.asFlatStaticArray.
And its implementation is this:
return *(cast(MultidimensionalStaticArrayElementType!(T, n)
[multidimensionalStaticArrayElementsCount!(T, n)]*) &t);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought more about this and a rank function that yields the dimensionality of an array (be it static or dynamic) may be useful. Since the first line in the documentation is "Gets the rank..." let's just call it rank
. As such these should pass:
static assert(rank!int == 0);
static assert(rank!(int[]) == 1);
static assert(rank!(int[42]) == 1);
static assert(rank!(int[7][8]) == 2);
static assert(rank!(int[42][]) == 2);
static assert(rank!(int[][42]) == 2);
static assert(rank!(int[][]) == 2);
A corresponding staticRank
could be defined but I don't think it has much generic utility to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can think as much as you want but I have never ever any idea why such rank
may be needed. And as the opposite, staticRank
is needed for practical use in my other functions.
The behavior of void main()
{
immutable(char)[9] s = "日本語";
alias typeof(s) S;
"MultidimensionalStaticArrayElementType!S: ".writeln(MultidimensionalStaticArrayElementType!S.stringof);
"ElementType!S: ".writeln(ElementType!S.stringof);
"ElementEncodingType!S: ".writeln(ElementEncodingType!S.stringof);
} produces
Suggest chaning introducing template MultidimensionalStaticArrayElementType(T, size_t n = staticArrayDimensions!T)
{
static assert(staticArrayDimensions!T >= n, "Not enough static array dimensions");
static if (n > 1)
alias MultidimensionalStaticArrayElementType!(ElementEncodingType!T, n-1) MultidimensionalStaticArrayElementType;
else static if (n == 1)
alias ElementType!T MultidimensionalStaticArrayElementType;
else
alias T MultidimensionalStaticArrayElementType;
}
template MultidimensionalStaticArrayElementEncodingType(T, size_t n = staticArrayDimensions!T)
{
static assert(staticArrayDimensions!T >= n, "Not enough static array dimensions");
static if (n > 1)
alias MultidimensionalStaticArrayElementEncodingType!(ElementEncodingType!T, n-1) MultidimensionalStaticArrayElementEncodingType;
else static if (n == 1)
alias ElementEncodingType!T MultidimensionalStaticArrayElementEncodingType;
else
alias T MultidimensionalStaticArrayElementEncodingType;
} Hence the usecase: void main()
{
immutable(char)[9] s = "日本語";
alias typeof(s) S;
"MultidimensionalStaticArrayElementType!S: ".writeln(MultidimensionalStaticArrayElementType!S.stringof);
"MultidimensionalStaticArrayElementEncodingType!S: ".writeln(MultidimensionalStaticArrayElementEncodingType!S.stringof);
"ElementType!S: ".writeln(ElementType!S.stringof);
"ElementEncodingType!S: ".writeln(ElementEncodingType!S.stringof);
} And corresponding output:
|
To @monarchdodra: These functions are for template programming and behave like [EDITED] |
Added |
static assert(multidimensionalStaticArrayElementsCount!(int[][0]) == 0); | ||
--- | ||
*/ | ||
template multidimensionalStaticArrayElementsCount(T, size_t n = staticArrayDimensions!T) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/Elements/Element/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Can you send |
Are we really ok with these insanely long names? We'll be the laughing stock of Java programmers.. |
@AndrejMitrovic well, suggestions welcome... |
import std.traits;
import std.range;
template ElemCount(T, size_t dim = DimCount!T)
{
static if (dim == 0)
enum ElemCount = 0;
else
static if (is(T W : W[V], int V))
enum ElemCount = V + ElemCount!(W, dim - 1);
else
enum ElemCount = 0;
}
template DimCount(T)
{
static if (is(T W : W[V], int V))
enum DimCount = 1 + DimCount!W;
else
enum DimCount = 0;
}
template BaseElementType(T)
{
static if (isStaticArray!T)
alias BaseElementType!(ElementType!T) BaseElementType;
else
alias T BaseElementType;
}
template Flatten(T)
if (isStaticArray!T)
{
alias BaseElementType!T[ElemCount!T] Flatten;
}
void test()
{
static assert(ElemCount!(int[3][2][1], 1) == 1);
static assert(ElemCount!(int[3][2][1], 2) == 3);
static assert(ElemCount!(int[3][2][1], 3) == 6);
static assert(is(Flatten!(int[1][2][3]) == int[6u]));
static assert(is(Flatten!(int[][2][3]) == int[][5u]));
static assert(is(Flatten!(int[][][2][3]) == int[][][5u]));
int[1][2][3] mdimSArr;
alias Flatten!(typeof(mdimSArr)) FlatArr;
cast(FlatArr)mdimSArr = [1, 2, 3, 4, 5, 6];
assert(mdimSArr == [[[1], [2]], [[3], [4]], [[5], [6]]]);
} As for the |
|
||
static assert(is(typeof(asFlatStaticArray!2(mdimSArr)) == int[1][6])); | ||
assert(asFlatStaticArray!2(mdimSArr) == [[1], [2], [3], [4], [5], [6]]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can merge this to a part of std.conv.to
feature.
ref toImpl(S)(ref S source) if (isStaticArray!S) {
alias Elem = getStaticArrayTerminalElemType!S;
enum dim = getStaticArrayFlattenDIm!S;
return *cast(Elem[dim]*)&source;
}
unittest {
int[1][2][3] mdimSArr;
mdimSArr.to!(int[6]) = [1,2,3,4,5,6];
assert(mdimSArr == [[[1], [2]], [[3], [4]], [[5], [6]]]);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To @AndrejMitrovic: First, all you names are too short and can be treated differently. It's unacceptable for template code as it should be as verbose as possible to eliminate any possibility to do a mistake.
I'll never convince to use
It's much more complicated than mine: template multidimensionalStaticArrayElementCount(T, size_t n = staticArrayDimensions!T)
{
static assert(staticArrayDimensions!T >= n, "Not enough static array dimensions");
enum multidimensionalStaticArrayElementCount = T.sizeof / MultidimensionalStaticArrayElementType!(T, n).sizeof;
} Needles over-complication is error-prone. But maybe I'm the only one stupid person here who calls every error-prone concept dangerous and every other coder is so professional that such error-prone things doesn't affect him. Let's see:
Correct but less readable that mine: template staticArrayDimensions(T)
{
static if(isStaticArray!T)
enum staticArrayDimensions = 1 + staticArrayDimensions!(ArrayElementType!T);
else
enum staticArrayDimensions = 0;
} as IsExpression is proved to be obviousness and hard to remember so you create needles complications for code reader. Also IsExpression is too dangerous to use ( error-prone doesn't express even a small part of how IsExpression dangerous) even if you understand it because a single typo leads to IsExpression returning
Mine one: template MultidimensionalStaticArrayElementType(T, size_t n = staticArrayDimensions!T)
{
static assert(staticArrayDimensions!T >= n, "Not enough static array dimensions");
static if(n)
alias MultidimensionalStaticArrayElementType!(ArrayElementType!T, n-1) MultidimensionalStaticArrayElementType;
else
alias T MultidimensionalStaticArrayElementType;
} First, you decided that there is no need for Second, you decided to use
Mine is in #952 now. First, it doesn't work with non-arrays and it kills the only purpose of P.S.You just forced me to spend an hour listing you obvious mistakes and trying to proof you the fact that we must not use error-prone solutions which itself looks too obvious to even talk about. But even Walter did "Patterns of humans error" presentation once, so people really don't want to understand this fact for some reasons. |
I have to concur that these names are ridiculously long. They're completely unreasonable. At least abbreviate them (e.g. |
Looks like you just hate arrays. ) I can also say: "I see no reason to include ... to Phobos" about any trait in |
To summarize this - I think retrieving the rank and extracting the innermost element type may be of some utility. The parts that do so only for static arrays are of too narrow utility. @denis-sh could you please change this accordingly? (One possibility would be to generalize these beyond arrays, e.g. look at the type of x[0] and transitively chase its type until indexing is no longer possible.) |
To summarize, I completely disagree and will not do it. |
If you so hate all my additions I can mark it all |
But please note, that I will be forced then to duplicate its functionality for my phobos-additions library because it also uses these templates. |
OK, let's wait for others to chime in. One issue was that the supported functions (as I recall from another pull request) were also quite specialized. @denis-sh also please let's avoid allowing any debate transgress into the personal and subjective. Keep in mind that nobody hates you or your work and that progress is achieved by making good arguments, handling criticism properly, and respecting one another. You're doing great work and there's no need to penalize us all for it by making any discussion with you an exercise in cringing. Thanks. |
But you are definitely a Static Array Hater (nothing negative here). All things in |
Example: | ||
--- | ||
static assert(is(MultidimStaticArrayElementType!int == int)); | ||
static assert(is(MultidimStaticArrayElementType!(int[]) == int[])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should emulate what ElementType
is doing and result in void
if T
isn't a multidimensional, static array. It makes no sense to get a valid result for invalid input as this is doing now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I already wrote, no changes in this code. Is is practically needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this code exactly? In one of your other pull requests, I assume? This behavior seems fundamentally broken, and at the moment, I would be inclined to argue that the code using this needs to be changed. I'd have to see the other code to make a fully educated judgement, but what what you're doing here seems like when a boolean function chooses to return false
rather than throwing an exception when it hits an error condition that prevents it from actually determining the correct answer, and that's very broken behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this code exactly? In one of your other pull requests, I assume?
Yes. Search for referenced this pull request. And in phobos-additions project.
This behavior seems fundamentally broken, ...
No, it is intentional. The idea is that we have zero-dimentional static array. As a result every value is a static array and we don't need any special static array conditions in templated code any more. And I'm not just like this idea, I use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And as I said, it makes about as much sense to say that a multimensional static array isn't a static array as it does to say that a yellow car isn't a car.
I can see an argument for staticArrayDimensions!int
giving 0
, since that's obviously an error condition rather than a valid number of dimensions for an array. But MultidimensionalStaticArrayElementType
has no such error condition. It tries to treat scalars as if they were static arrays, which I contend makes no sense and is inconsistent with ElementType
. It should either give void
or not use a template constraint to prevent scalars working with it outright.
Clearly, we're not going to agree here, and this discussion is going nowhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And as I said, it makes about as much sense to say that a multimensional static array isn't a static array as it does to say that a yellow car isn't a car.
And in my opinion you are telling: a car parking without cars isn't a car parking.
Clearly, we're not going to agree here, and this discussion is going nowhere.
Of course! But thanks for your time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmdavis: this is a matter of dimensionality, not size, so bringing T[1]
into the discussion is a red herring. Consider a non-array type T
(int, double, class etc). On top of it we build array types of different dimensions: T[24]
, T[24][42]
etc. These have 1, 2, and so on dimensions. On occasion the dimensionality of T
itself comes into question, and the correct answer is it's 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0-dimensionality is something special imo:
alias byte[0] T1;
alias byte T2;
static assert(T1.sizeof == 0);
static assert(T2.sizeof == 1);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AndrejMitrovic uhm I didn't know that ever worked. But byte[0] is not a zero-dimensional array, it's a 1-dimensional array with length 0.
I don't know whether these are quite the right traits that we want, but I see no reason not to have traits for static arrays. If it's truly something that only a select few are likely to be using, then it's of questionable value, but while I don't use much in the way of static arrays, I know that quite a few other people in the newsgroup do, and it makes sense that at least some traits relating to them would be necessary as part of that. My largest complaint with this pull request is the overly verbose names. Abbreviation can be used to mitigate that however. I am against the idea of |
Can not even answer... Misunderstanding is terrible. I suppose you don't want to understand my opinion (and it's OK because I don't want to understand yours too). I will only repeat: let it be |
No, I will continue this time-wasting discussion. Sorry.
This is the point. These traits are for static arrays because there is absolutely no support for it in the library now. |
I meant the name |
My problem with the name |
A small note: a rank of a matrix in linear algebra (which multidimensional static arrays often represent) is something different then the number of dimensions. While it's a trait applied to a type so the math notion can't be attributed to it I stil suspect that say just dimensions would be far less confusing. Again maybe making this discussion even worse but is there any disadvantage of having dimensions (or arrayDimensions) to work for arrays of both types. Basically why the exclusivness? If need exclusivness could be replaced by something along the lines of : |
The problem is something like int[][4] a; or int[4][][] b; What would |
I agree with your notion of dimensions being that of the outer one multi-dimensional array. The way I describe 'a' is static array of dynamic arrays of int. Then 'dynamic array of dynamic array' is 2-dimensional dynamic array and same would go for 'static array of static array' as 2-dimensional static array. But clarification in docs should be present regradless of logic as it's tempting to just count pairs of brackets and call it a dimension. |
What is the state of this? |
Rebased on |
/** | ||
Gets the rank (number of dimensions) of a static array type. | ||
*/ | ||
template staticArrayDims(T) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not intuitive or obvious that this returns 0 when given a non-static-array type, so it either needs to be disallowed with a template constraint or included in the documentation. I think disallowing it is probably the right choice.
edit:
I see that multiDimStaticArrayElementCount
depends on this, but that doesn't justify compromising a user-facing interface, there are plenty of ways to work around that.
My latest line comments are based on the pull request as-is; that is, these templates are documented and public. In that vein, I have to say I really dislike the names. I think there are shorter and more memorable names available without resorting to abbreviations, like Existing names in So, mostly repetition of what has been said, but ultimately that's because the issues have not been resolved. If you're going to make these internal, then you should do so and present the PR as such. |
The whole idea is the ability to forget about static arrays as a special case and introduce zero-dimensional static array. In contrast to I'm for better names but looks like they are already as short as possible. Proposals are welcome. |
Regarding to documentation I suppose |
OK. Clarified documentation to make things obvious. |
* adds `staticArrayDims` * adds `MultidimStaticArrayElementType` * adds `multidimStaticArrayElementCount`
Documentation here: unstd.traits docs.
Additions:
staticArrayDims
MultiDimStaticArrayElementType
multiDimStaticArrayElementCount