-
-
Notifications
You must be signed in to change notification settings - Fork 607
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
Add new builtin trait isCopyable #10575
Conversation
Thanks for your pull request and interest in making D better, @nordlow! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#10575" |
Needs a changelog. |
Done. |
@@ -0,0 +1,5 @@ | |||
Add new builtin `__traits(isCopyable, T)` for some type `T` | |||
|
|||
Changing Phobos' `std.traits.isCopyable` to make use of this new builtin trait |
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.
The function mtype.isCopyable()
in its current form may yield different results from std.traits.isCopyable
since it doesn't check the copy constructor.
import std;
struct S
{
@disable this(ref S);
}
pragma(msg, isCopyable!S); // false
pragma(msg, __traits(isCopyable, S)); // true
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.
Do you have a suggestion for how to check for a disabled copy constructor? Should I copy the logic from e.ident == Id.hasCopyConstructor
?
Further, should we add this copy constructor checking directly into isCopyable
in mtype.d
or only inside the new if-statement in traits.d
?
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 need to check if there is a matching copy constructor overload for your type. It should be inside isCopyable
.
This should do if you remove the nothrow pure @nogc
attributes.
if (ts.sym.hasCopyCtor)
{
// check if there is a matching overload of the copy constructor and whether it is disabled or not
Dsymbol ctor = search_function(cast() ts.sym, Id.This);
assert(ctor);
scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
el.type = cast() ts;
Expressions args;
args.push(el);
FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, &args, FuncResolveFlag.quiet);
if (!f || f.storage_class & STC.disable)
return false;
}
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. Added a matching test aswell.
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.
FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, &args, FuncResolveFlag.quiet);
Is there now direct way of looking up the specific constructor that takes ref typeof(this)
as single parameter?
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 guess you want to cache the result instead of trying every overload every time. I don't think it's done yet. If you want to do it, it has to be stored on the TypeStruct instead of the StructDeclaration because there can be multiple types with different type modifiers (const, immutable, shared... etc) which all share the same StructDeclaration but each will match a different overload of the copy constructor.
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.
Can we add this caching in another pull request?
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.
Since it's not required, yes.
Here's the library implementation:
I'm not really seeing much point it building it in to the compiler. Also, this PR should include the tests from the Phobos version. |
Yes, this is a microoptimization for eliding parsing of the |
auto-tester passes but in line 6768 containing assert(ctor); fails. Should this assert be replaced by if (ctor is null) { return true; } ? |
The assertion fails because I made a mistake in the code snippet, it should be |
Done. |
Ready to merge. |
I can't figure out why the Windows_OMF x64 build fails. |
Seems like the CI does not like your name ... /s
|
So what to do? |
It's not a required CI, so maintainers can just force-merge it if this gets approved. https://github.com/dlang/dmd/blob/master/test/dshell/sameenv.d You could probably add a filter for |
This has been approved by @SSoulaimane |
Are you saying I could try modifying this code to support names containing the letter |
Well, while that would the ideal solution, I said either ignoring the failure or filtering the respective environment variable out should be fine as well.
Yes, but Walter's objection hasn't been addressed. |
Do you still oppose adding this, @WalterBright? |
I think benchmarks before and after this PR would be very persuasive in convincing @WalterBright to pull this request. |
ping @nordlow |
What kinds of benchmarks do you propose? Iterating over a large set of types via |
I propose that you create a compile speed benchmark of the the trait "IsCopyable" when implement via library vs built in trait that your PR Contain. You need to show that there are significant improvements when built into the compiler. |
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 needs benchmark test, otherwise lgtm.
Thanks! |
No benchmark is done, which is odd because in the opening statement here you had a project that used it a lot, but there's no mention of what (if any) performance gains were realized on it. The point of benchmarking is to figure out which of std.traits are worthwhile to find faster solutions to. There are a lot of them. Doing them randomly is not very practical. As far as I can see, there is no rationale for doing isCopyable. |
The following contrived benchmark import std.traits : isCopyable;
import std.meta : AliasSeq;
struct W(T, size_t n)
{
T value;
}
@safe pure unittest
{
alias Ts(uint n) = AliasSeq!(W!(byte, n), W!(ubyte, n),
W!(short, n), W!(ushort, n),
W!(int, n), W!(uint, n),
W!(long, n), W!(ulong, n),
W!(float, n), W!(cfloat, n),
W!(double, n), W!(cdouble, n),
W!(real, n), W!(creal, n),
W!(string, n), W!(wstring, n), W!(dstring, n));
enum n = 100;
enum m = 100;
static foreach (i; 0 .. n)
{
foreach (T; Ts!(n))
{
static foreach (j; 0 .. m)
{
static assert(__traits(isCopyable, T));
// static assert(isCopyable!(T));
}
}
}
} semantically checks in 0.9 s with On pro of adding this builtin trait and reusing it in the implementation of |
Thank you, Per. |
@nordlow Could you please also make a PR to dlang.org which adds this to the language specification / grammar? |
Yep. See dlang/dlang.org#3025 |
I'm using
std.traits.isCopyable
all over the place to make my containers as generic as possible. So why not reuse the already existingisCopyable()
in mtype.d to further optimize compilation.