-
-
Notifications
You must be signed in to change notification settings - Fork 741
Fix predicate template implementations in std.traits and std.range #842
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
@@ -551,7 +551,7 @@ template isInputRange(R) | |||
enum bool isInputRange = is(typeof( | |||
(inout int _dummy=0) | |||
{ | |||
R r = void; // can define a range object | |||
R r = R.init; // can define a range object |
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.
Is there a difference between this and R r;
?
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.
R r;
fails if R
is a struct with disabled default construction.
Are you asking whether or not such structs should be valid ranges?
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.
If R
has @disable this();
, R r;
is not allowed.
To solve the problem, I had changed to R r = void;
, but it has still problem if R
is const or immutable type.
(const
/immutable
range is almost meaningless, but it is syntactically allowed). Then, use R.init
is better.
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 see, thanks. I find it very arcane to rely on this kind of trickery to distinguish between types with disabled default constructor and the others. Any other ideas for a simpler way?
I just realized something - there are two ways to create a value of a non-copyable type:
(*cast(T*) null) That works great if the only need is to check whether something compiles without having to construct an object
union { T t; }; Putting anything in a union should guarantee no constructor or destructor is ever called. Currently the compiler doesn't do that, there's a bug report about that: http://d.puremagic.com/issues/show_bug.cgi?id=4421. |
Just want to point out: http://d.puremagic.com/issues/show_bug.cgi?id=8762 I propose that It is guaranteed to work for ALL types At this point, the implementations can safely use, no questions asked: template isOutputRange(R, E)
{
enum bool isOutputRange = is(typeof(
(inout int _dummy=0)
R r = defaultInit!R;
E e = defaultInit!E;
put(r, e);
}));
} I think it is a good proposal, no? Heck, one can then even dispense the declaration of r/e, and do a straight up: template isOutputRange(R, E)
{
enum bool isOutputRange = is(typeof(put(defaultInit!R, defaultInit!E)));
} Which also has the advantage of ditching the whole _dummy function too... Added bonus, because it is a function, it can even work on a value type, making it easy to extract a value out of an LValue out of an expression:
PS: defaultInit is private right now, so I won't complain, but if it ever becomes public, I really think |
I think |
Because a void static array type (e.g. |
Furthermore, |
@@ -112,14 +112,50 @@ private | |||
alias TypeTuple!(IntegralTypeList, FloatingPointTypeList) NumericTypeList; | |||
alias TypeTuple!(char, wchar, dchar) CharTypeList; | |||
|
|||
/* Get an expression typed as T, like T.init */ | |||
template hasWild(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.
I know this is terminology from DMD, but I think hasInout
is better.
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.
OK. Fixed.
@9rnsr should we move forward with this or wait for a compiler change to allow |
Now, I have proposed a language enhancement issue 8819 for |
@9rnsr this needs a rebase |
Finally, by fixing issue 8819, all types have .init property right now. So no trick is necessary. We can use |
@@ -113,17 +113,55 @@ private | |||
alias TypeTuple!(cfloat, cdouble, creal) ComplexTypeList; | |||
alias TypeTuple!(IntegralTypeList, FloatingPointTypeList) NumericTypeList; | |||
alias TypeTuple!(char, wchar, dchar) CharTypeList; | |||
|
|||
template hasInout(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.
Hmm.. we should have some kind of TargetType
template which does what this template does, and then this kind of template would be implemented as static if (is(TargetType!T == inout))
. ElementType
comes close but I'm not sure if it works with pointers and associative arrays. This would avoid code duplication for future templates like this one.
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.
So this is undocumented for 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.
Yes. I'd like to keep internal templates private until it is really 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.
Fine with me.
So, does that mean that just meant that |
I think |
#1261 is merged and |
Just want to point out we also have is(typeof(
(inout int = 0)
{
R r = R.init;
E e;
put(r, e);
} Could simply be: is(typeof(
(inout int = 0)
{
put(lvalueOf!R, rvalueOf!E);
} Worst case scenario, if we need the variable more than once: alias r = lvalueOf!R;
r.popBack();
auto t = r.back;
auto w = r.front; |
Didn't think about that. Looks clear and consistent especially with new alias syntax! |
Status of this? |
The whole things looks obsolete to me now (IMO). |
I reopen this PR, because using |
@andralex Ping. |
@9rnsr @andralex
If anything I'd say go for public primitives in the implementation (else what good they are). |
I think using
|
Yeah, right lvalueOf would require a copy during
|
@9rnsr : "Note that using lvalueOf is not correct" : Are you saying that it produces wrong result, or is just not the best thing to use here? I think this pull is correct, and better than before, so I think it is pull worthy. Bet I still have some trouble accepting that this: enum bool isOutputRange = is(typeof(
(inout int = 0)
{
R r = R.init;
E e = E.init;
put(r, e);
})); is better than this: enum bool isOutputRange = is(typeof(put(lvalueOf!R, lvalueOf!E))); Questions: Are If we can't use them for this, then they kind of fail for the very thing they were meant to solve... |
I meant that: "lvalueOf would require a copy during T val = lvalueOf!T;"
Actually we had had same expensive cost around isXXX and XXXTypeOf templates in std.traits. Now the cost is fundamentally reduced by |
True, but if you go ahead and use enum bool isOutputRange = is(typeof(
(inout int = 0)
{
alias r = lvalueOf!R;
alias e = lvalueOf!E;
put(r, e);
})); Or, the 1-liner I showed above:
I'm not sure these are comparable, since the
|
@9rnsr : rebase this and I'll pull it. As I said, I don't completely agree with approach, but it is still better than before. |
It was a hack for the compiler bugs around T.init. Now the they are properly fixed, so the unused helper function is actually unnecessary.
Use T.init property instead of void initializer, because it will work even if T is const or immutable type. I must change a part of unit test for the bug 6935, because we cannot support ranges which overrides init property.
OK, rebased commits. |
Fix predicate template implementations in std.traits and std.range
Merged! Finally :) Thanks. |
Use T.init property instead of void initializer, because it doesn't work if T is const or immutable type.
I must change a part of unit test for the bug 6935, because we cannot support ranges which overrides init property.
From the mention by @donc, using
= void
in predicate is sometimes not good. Then we should useT.init
or library solution (e.g.defaultInit
in std.traits).For almost cases,
T.init
is enough. But, void static array types don't have.init
property. Then, if we want to treat all types,defaultInit
is necessary I think.(Furthermore, it seems to me acceptable that default initialized void static arrays have zero filled memory. But it is language spec issue.)