Skip to content

Make some traits iterative using static foreach#6402

Merged
dlang-bot merged 1 commit intodlang:masterfrom
nordlow:iterative-traits
Oct 23, 2018
Merged

Make some traits iterative using static foreach#6402
dlang-bot merged 1 commit intodlang:masterfrom
nordlow:iterative-traits

Conversation

@nordlow
Copy link
Contributor

@nordlow nordlow commented Apr 1, 2018

This reduces the number of template instantiations needed and is measured to be at least as fast as the recursive variants here.

The refactored traits are: genericIndexOf, allSatisfy, anySatisfy, isExpression and allSameType.

There a probably more traits that could benefit from this refactoring. Proposals are welcome.

if we added a static break; to exit a static foreach prematurely, would that speed up the compilation even further, @WalterBright?

@dlang-bot
Copy link
Contributor

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 verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the annotated coverage diff directly on GitHub with CodeCov's browser extension
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

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 references

Your 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 locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub fetch digger
dub run digger -- build "master + phobos#6402"

@wilzbach
Copy link
Contributor

wilzbach commented Apr 1, 2018

if we added a static break; to exit a static foreach prematurely, would that speed up the compilation even further

Yeah that would be really cool.
FWIW this was even proposed in DIP1010:

https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md#static-break-and-static-continue

It also comes up in the NG from time to time:

https://forum.dlang.org/post/mailman.2099.1515541202.9493.digitalmars-d-learn@puremagic.com

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!
Interestingly this triggers an ICE when building the docs for std.meta (see DAutoTest)

std/meta.d Outdated
// [internal]
private template genericIndexOf(args...)
if (args.length >= 1)
if (args.length >= 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std/meta.d(304:9)[warn]: If constraints should have the same indentation as the function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

enum index = 0;
}
else
static if (is(typeof(genericIndexOf) == void) && // not yet defined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice trick 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

std/meta.d Outdated
alias tuple = args[1 .. $];

static if (tuple.length)
static foreach (idx, argi; args[1 .. $])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Why not "arg" instead of "args" (it's a typical convention to denote the array with a "s" postfix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

std/traits.d Outdated
static foreach (Ti; T)
{
static if (!is(typeof(isExpressions) == bool) && // not yet defined
!is(T[0]) && __traits(compiles, { auto ex = T[0]; }))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be Ti here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Fixed. Thanks!

Copy link
Member

@andralex andralex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please mind @wilzbach 's review

std/meta.d Outdated
// [internal]
private template genericIndexOf(args...)
if (args.length >= 1)
if (args.length >= 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we keep constraints flush with the declaration they constrain

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

enum index = 0;
}
else
static if (is(typeof(genericIndexOf) == void) && // not yet defined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow

@nordlow nordlow force-pushed the iterative-traits branch from b7df9de to 2240075 Compare April 3, 2018 22:43
Copy link
Contributor Author

@nordlow nordlow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All comments fixed.

std/meta.d Outdated
// [internal]
private template genericIndexOf(args...)
if (args.length >= 1)
if (args.length >= 1)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

std/meta.d Outdated
// [internal]
private template genericIndexOf(args...)
if (args.length >= 1)
if (args.length >= 1)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

std/meta.d Outdated
alias tuple = args[1 .. $];

static if (tuple.length)
static foreach (idx, argi; args[1 .. $])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

enum index = 0;
}
else
static if (is(typeof(genericIndexOf) == void) && // not yet defined
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

std/traits.d Outdated
static foreach (Ti; T)
{
static if (!is(typeof(isExpressions) == bool) && // not yet defined
!is(T[0]) && __traits(compiles, { auto ex = T[0]; }))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Fixed. Thanks!

@nordlow
Copy link
Contributor Author

nordlow commented Apr 3, 2018

Should be ready now. Can you find any other traits that can be made iterative?

Found one: allSameType...hang on...I'll make that iterative too.

@nordlow nordlow force-pushed the iterative-traits branch from 2240075 to 486d7e0 Compare April 3, 2018 23:08
@nordlow
Copy link
Contributor Author

nordlow commented Apr 3, 2018

Ready now!

static if (!is(typeof(allSameType) == bool))
{
enum bool allSameType = is(T[0] == T[1]) && allSameType!(T[1..$]);
enum bool allSameType = true;
Copy link
Contributor

@wilzbach wilzbach Apr 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm looks like DScanner's check is bogus here:

std/traits.d(8419:19)[warn]: Variable "allSameType" has the same name as a variable defined on line 8414.

I don't know why the other very similar code is accepted though.
However, you can ignore this module for this check by adding the following to the ModuleFilter blacklist in the .dscanner.ini

label_var_same_name_check="-std.traits"

(Ideally preceded by a reference to a DScanner issue)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@nordlow
Copy link
Contributor Author

nordlow commented Apr 3, 2018

Thanks, @wilzbach.

@nordlow
Copy link
Contributor Author

nordlow commented Apr 3, 2018

I don't know why Win32 fails...

@andralex
Copy link
Member

andralex commented Apr 4, 2018

@nordlow try wine

@wilzbach
Copy link
Contributor

wilzbach commented Apr 4, 2018

There's an ICE on Linux too (when run with -D):

core.exception.AssertError@dmd/cond.d(378): Assertion failure
----------------
??:? _d_assertp [0x74903d]
dmd/cond.d:378 pure nothrow @nogc @safe void dmd.cond.StaticForeach.prepare(dmd.dscope.Scope*).__require() [0x51392f]
dmd/cond.d:377 void dmd.cond.StaticForeach.prepare(dmd.dscope.Scope*) [0x5137dc]
dmd/attrib.d:1083 _ZN24StaticForeachDeclaration7includeEP5Scope [0x50c2df]
dmd/doc.d:1042 _ZN11emitComment11EmitComment5visitEP17AttribDeclaration [0x55811b]
dmd/parsetimevisitor.d:75 _ZN16ParseTimeVisitorI10ASTCodegenE5visitEP24StaticForeachDeclaration [0x6437f2]
dmd/attrib.d:1143 _ZN24StaticForeachDeclaration6acceptEP7Visitor [0x50c48d]
dmd/doc.d:1091 void dmd.doc.emitComment(dmd.dsymbol.Dsymbol, dmd.root.outbuffer.OutBuffer*, dmd.dscope.Scope*) [0x557798]
dmd/doc.d:796 void dmd.doc.emitMemberComments(dmd.dsymbol.ScopeDsymbol, dmd.root.outbuffer.OutBuffer*, dmd.dscope.Scope*) [0x55767c]
dmd/doc.d:916 _ZN11emitComment11EmitComment4emitEP5ScopeP7DsymbolPKc [0x557c57]
dmd/doc.d:960 _ZN11emitComment11EmitComment5visitEP11Declaration [0x557ded]
dmd/parsetimevisitor.d:47 _ZN16ParseTimeVisitorI10ASTCodegenE5visitEP16AliasDeclaration [0x643492]
dmd/declaration.d:929 _ZN16AliasDeclaration6acceptEP7Visitor [0x535d61]
dmd/doc.d:1091 void dmd.doc.emitComment(dmd.dsymbol.Dsymbol, dmd.root.outbuffer.OutBuffer*, dmd.dscope.Scope*) [0x557798]
dmd/doc.d:796 void dmd.doc.emitMemberComments(dmd.dsymbol.ScopeDsymbol, dmd.root.outbuffer.OutBuffer*, dmd.dscope.Scope*) [0x55767c]
dmd/doc.d:439 _Z10gendocfileP6Module [0x556783]
dmd/mars.d:911 int dmd.mars.tryMain(ulong, const(char)**) [0x5f8097]
dmd/mars.d:1098 _Dmain [0x5f8d92]

reported -> https://issues.dlang.org/show_bug.cgi?id=18721

@wilzbach
Copy link
Contributor

wilzbach commented Apr 4, 2018

@nordlow you could also try to split this PR into smaller ones, e.g. the documentation ICE comes from allSameType

@wilzbach
Copy link
Contributor

wilzbach commented Apr 4, 2018

Oh and I think the persistent Windows access violation means that there are now too many symbols in the OMF object file (the maximum is 32768).
So I assume another "split-up" of phobos.lib is required :/
See also: https://issues.dlang.org/show_bug.cgi?id=4904

Copyright (C) Digital Mars 2000-2007

We really need to switch to a more modern, actively maintained linker ...

@nordlow
Copy link
Contributor Author

nordlow commented Apr 4, 2018

@wilzbach, can I run ddoc generation on phobos via a CLI-call to `make``?

@wilzbach
Copy link
Contributor

wilzbach commented Apr 4, 2018

@wilzbach, can I run ddoc generation on phobos from the makefile?

Well you need to clone dlang.org first, e.g.

cd ~/dlang
git clone https://github.com/dlang/dlang.org
make -f posix.mak phobos-prerelease -j4

and then check web/phobos-prerelease

Though for the failure you don't need any macros, just dmd -D <file> should be enough.

reported -> https://issues.dlang.org/show_bug.cgi?id=18721

BTW my noobish attempt: dlang/dmd#8128 (though the ICE I reduced looks a bit different)

@andralex
Copy link
Member

status?

@nordlow
Copy link
Contributor Author

nordlow commented Apr 22, 2018

Made a merge against master to see if something has changed (for the better).

@andralex, see @wilzbach comments regarding too many symbois in the OMF symbols file. I assume a split of this PR will still (in the end) result in the same Win32-only linking problem, right? @WalterBright ?

@nordlow
Copy link
Contributor Author

nordlow commented Oct 23, 2018

I did a merge against master to see if the linking error still occurs on Windows. What's the best way of fixing the too-many-symbol-problem @wilzbach mentioned above?

@nordlow
Copy link
Contributor Author

nordlow commented Oct 23, 2018

Build passes. Ok to merge @andralex?

@wilzbach
Copy link
Contributor

Please rebase instead of merging for a slicker git history.

@wilzbach
Copy link
Contributor

Regarding the linker error: looks like you are lucky and symbols have been moved around in the last six months. As long as auto-tester is green, everything should be okay.

@nordlow
Copy link
Contributor Author

nordlow commented Oct 23, 2018

Great @wilzbach. Rebase done.

;imports_sortedness="-etc.c.curl,-std.algorithm.comparison,-std.algorithm.internal,-std.algorithm.iteration,-std.algorithm.mutation,-std.algorithm.searching,-std.algorithm.setops,-std.algorithm.sorting,-std.array,-std.bigint,-std.bitmanip,-std.c.freebsd.socket,-std.c.linux.pthread,-std.c.process,-std.complex,-std.concurrency,-std.container.array,-std.container.binaryheap,-std.container.dlist,-std.container.rbtree,-std.container.slist,-std.container.util,-std.conv,-std.datetime,-std.datetime.date,-std.datetime.interval,-std.datetime.systime,-std.datetime.timezone,-std.digest,-std.digest.hmac,-std.exception,-std.experimental.allocator,-std.experimental.allocator.building_blocks,-std.experimental.allocator.building_blocks.affix_allocator,-std.experimental.allocator.building_blocks.allocator_list,-std.experimental.allocator.building_blocks.free_list,-std.experimental.allocator.building_blocks.free_tree,-std.experimental.allocator.building_blocks.kernighan_ritchie,-std.experimental.allocator.building_blocks.region,-std.experimental.allocator.common,-std.experimental.allocator.mallocator,-std.experimental.allocator.mmap_allocator,-std.experimental.allocator.showcase,-std.experimental.allocator.typed,-std.experimental.checkedint,-std.experimental.logger.core,-std.experimental.typecons,-std.file,-std.format,-std.functional,-std.getopt,-std.internal.math.biguintcore,-std.internal.test.dummyrange,-std.json,-std.math,-std.meta,-std.mmfile,-std.net.curl,-std.net.isemail,-std.numeric,-std.outbuffer,-std.parallelism,-std.path,-std.process,-std.random,-std.range,-std.range.primitives,-std.regex,-std.regex.internal.backtracking,-std.regex.internal.generator,-std.regex.internal.kickstart,-std.regex.internal.parser,-std.regex.internal.tests,-std.signals,-std.socket,-std.stdio,-std.string,-std.uni,-std.utf,-std.uuid,-std.variant,-std.windows.charset,-std.windows.registry,-std.windows.syserror,-std.zip"
; Checks for labels with the same name as variables
label_var_same_name_check="-std.algorithm.iteration,-std.algorithm.sorting,-std.array,-std.bigint,-std.bitmanip,-std.conv,-std.encoding,-std.experimental.allocator.building_blocks.segregator,-std.experimental.typecons,-std.format,-std.internal.digest.sha_SSSE3,-std.parallelism,-std.process,-std.typecons,-std.utf"
label_var_same_name_check="-std.algorithm.iteration,-std.algorithm.sorting,-std.array,-std.bigint,-std.bitmanip,-std.conv,-std.encoding,-std.experimental.allocator.building_blocks.segregator,-std.experimental.typecons,-std.format,-std.internal.digest.sha_SSSE3,-std.parallelism,-std.process,-std.typecons,-std.utf,-std.traits"
Copy link
Contributor Author

@nordlow nordlow Oct 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still needed @wilzbach ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't recall that this would have been fixed on the dscanner side. Though opening an issue there might help.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, ok to keep as is then so we can pull this?

Copy link
Member

@andralex andralex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

@dlang-bot dlang-bot merged commit 6c448be into dlang:master Oct 23, 2018
@nordlow
Copy link
Contributor Author

nordlow commented Oct 24, 2018

Thanks.

@nordlow
Copy link
Contributor Author

nordlow commented Oct 24, 2018

We really need to switch to a more modern, actively maintained linker ...

Will this keep on hindering us in development?

n8sh added a commit to n8sh/druntime that referenced this pull request Oct 25, 2018
n8sh added a commit to n8sh/druntime that referenced this pull request Oct 25, 2018
dlang-bot added a commit to dlang/druntime that referenced this pull request Oct 25, 2018
Port more efficient allSatisfy/anySatisfy from dlang/phobos#6402
merged-on-behalf-of: Sebastian Wilzbach <sebi.wilzbach@gmail.com>
@nordlow nordlow deleted the iterative-traits branch October 31, 2018 09:44
@Hackerpilot
Copy link
Contributor

This introduced an undocumented change: https://issues.dlang.org/show_bug.cgi?id=19560

I'm not really sure that I want to call it a regression because the new behavior makes more sense than the old, and the old behavior wasn't really specified.

@andralex
Copy link
Member

andralex commented Jan 8, 2019

Good catch. I think what was not specified and becomes specified should be documented carefully but not count as a regression.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants