[Static if] replace overload constraints with static if (iteration.d)#5148
[Static if] replace overload constraints with static if (iteration.d)#5148dlang-bot merged 1 commit intodlang:masterfrom
Conversation
58a5659 to
75eb742
Compare
wilzbach
left a comment
There was a problem hiding this comment.
I grouped the overloads into byValue and possibly byReference (aka auto ref)
| import std.meta : AliasSeq; | ||
| import std.traits : Parameters; | ||
|
|
||
| private: |
There was a problem hiding this comment.
Technically this is a "breaking" change, but IIRC non-documented members can be set to private without deprecation path is the user can only know about them by reading the code on his own and no guarantees were given.
There was a problem hiding this comment.
I came to see label: as a near antipattern - it's too nonlocal and makes code difficult to understand and review without context. @wilzbach how about a rule that prevents at least the use of private: and public: in phobos?
| if (isRangeIterable!Range && !isForeachIterable!Range) | ||
| if (!isForeachIterable!Range && ( | ||
| isRangeIterable!Range || | ||
| __traits(compiles, typeof(r.front).length))) |
There was a problem hiding this comment.
This change groups the first and third overload and the second + fourth, respectively as the latter ones might have their input as reference. So this overload is for calling with args given by-Value:
There was a problem hiding this comment.
Did you mean the 1st and 4th overloads are grouped as one group, and the 2nd and 3rd as another group? I'm looking at the code and the sig constraints of the 1st and 3rd, taken together, don't match what you have here.
There was a problem hiding this comment.
Assuming you meant that the 1st and 4th overloads are grouped together, the code looks OK to me.
75eb742 to
2e15d8a
Compare
There was a problem hiding this comment.
The code itself looks good, but I feel it falls short of the goal. While we have reduced 4 overloads to 2, as far as the user's POV is concerned, esp. wrt. the ddocs, these overloads are still somewhat inscrutable.
For example, the first overload's sig constraints refers to isRangeIterable, which is now not only an undocumented trait, but a private one. Furthermore, there's the ugly __traits(compiles, ...) the intent of which is unclear.
Taking a step back, let's look at this entire overload set. AIUI the reason we can't put everything into a single overload is because of the auto ref in the second group, an understandable distinction. The primary reason for this distinction seems to be that one group deals with things that support foreach whereas the other group deals with things that don't support foreach but do at least have a range API.
So from the user's POV, the sig constraints really should look something like this:
void each(Range)(Range r)
if (!isForeachIterable!Range && isInputRange!Range)
{ ... }
void each(Range)(auto ref Range r)
if (isForeachIterable!Range)
{ ... }
(And on that note, the original isRangeIterable trait is misleadingly named, because what it really means is "range-iterable with a single index". And the funny-looking __traits(compiles...) check appears to be trying to ensure that any subranges aren't infinite or have unknown length, which would make it impossible to be passed to pred.)
I would say those should be the public-facing sig constraints, and inside the overload bodies, the static ifs must check for all constraints pertaining to that code block, especially in the else branch, and there should be a final else assert(0,...); to catch any cases that the current implementation doesn't support, with of course an appropriate error message indicating what went wrong.
| if (isRangeIterable!Range && !isForeachIterable!Range) | ||
| if (!isForeachIterable!Range && ( | ||
| isRangeIterable!Range || | ||
| __traits(compiles, typeof(r.front).length))) |
There was a problem hiding this comment.
Assuming you meant that the 1st and 4th overloads are grouped together, the code looks OK to me.
| void each(Iterable)(auto ref Iterable r) | ||
| if (isForeachIterable!Iterable) | ||
| if (isForeachIterable!Iterable || | ||
| __traits(compiles, Parameters!(Parameters!(r.opApply)))) |
There was a problem hiding this comment.
The code for the second group checks out as well (assuming you meant they correspond with the 2nd and 3rd overloads in the original).
|
And just for the record, the last bit is what I meant in various forum posts that user-facing overloads should have sig constraints that reflect intent rather than implementation: the intent of There may be, however, some ranges that satisfy these constraints but which aren't handled by the current implementation; these should be caught by the final |
| import std.meta : AliasSeq; | ||
| import std.traits : Parameters; | ||
|
|
||
| private: |
There was a problem hiding this comment.
I came to see label: as a near antipattern - it's too nonlocal and makes code difficult to understand and review without context. @wilzbach how about a rule that prevents at least the use of private: and public: in phobos?
|
Jenkins doesn't build and clicking the link goes to |
I would point out that aside from the fact that druntime and Phobos use Now, I tend to agree that mass-applying attributes is a problem, but to be honest, I think that using Regardless, for better or worse, the current trend seems to be headed in the opposite direction of avoiding |
|
@wilzbach I noticed that this (nonsensical) example from issue 15459 doesn't compile any more, do you think it indicates a regression? I couldn't come up with a meaningful variation that would manifest as a regression. import std.stdio;
import std.algorithm;
char somefunc(char c)
{
return c;
}
void main()
{
stdin
.byLine
.each!(map!somefunc);
} |
Hmm, auto-decoding has been a thing in Phobos for a long, long time - so no I don't think it's a regression. On the contrary, now at least you get a compiler error. With 2.074.0 |
|
Right, but is the compiler error fixing (correctly replacing) the link error, or just making it unreproducible with that example? |
Split up of #5145