Skip to content

Implement aliasSeqOf for all iterables#5630

Merged
dlang-bot merged 8 commits intodlang:masterfrom
John-Colvin:improve_aliasSeq
May 9, 2019
Merged

Implement aliasSeqOf for all iterables#5630
dlang-bot merged 8 commits intodlang:masterfrom
John-Colvin:improve_aliasSeq

Conversation

@John-Colvin
Copy link
Contributor

Hooray for static foreach 👍

@dlang-bot
Copy link
Contributor

dlang-bot commented Jul 18, 2017

Thanks for your pull request and interest in making D better, @John-Colvin! 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#5630"

{
static assert(false, "Cannot transform range of type " ~ ArrT.stringof ~ " into a AliasSeq.");
}
static foreach (size_t i, el; iter.array)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Solutions that didn't use std.array.array seemed more complicated than they were worth (which is probably not much, thinking of how current CTFE and newCTFE work).

Copy link
Member

Choose a reason for hiding this comment

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

I'm sure @UplinkCoder would know.

Copy link
Member

Choose a reason for hiding this comment

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

don't use .array please.
instead introduce a counter variable into the parent-scope.

Copy link
Member

Choose a reason for hiding this comment

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

also.
Keep that: alias aliasSeqOf = AliasSeq!(aliasSeqOf!(range[0 .. $/2]), aliasSeqOf!(range[$/2 .. $]));
As it avoids factorial blow-up.

Copy link
Contributor Author

@John-Colvin John-Colvin Jul 19, 2017

Choose a reason for hiding this comment

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

I'm pretty sure a counter variable isn't an option unless I take the whole struct contents in to one big mixin. array is also handing autodecoding (makes me sad).

W.r.t. the recursive template, I was afraid you'd say that. So the story with static foreach is "here's a great new feature, don't use it, it's too slow"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ping @UplinkCoder, I'd like to understand this better, because static foreach is just so very convenient.

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't be afraid too of using static foreach.
Entire Phobos uses it nowadays (-> #5989) and there was no measurable difference in the build time of the entire testsuite.

(Granted this doesn't say much about the extra-allocation of .array)

Copy link
Member

@MetaLang MetaLang left a comment

Choose a reason for hiding this comment

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

I love how much more concise and simple this code is with static foreach.

Edit: it also looks like it's consistently segfaulting on Win32. Not sure if that's related to this PR or not... may be due to some weird interaction between static foreach and the CT heap allocation.

std/meta.d Outdated
if (isIterable!(typeof(iter)))
{
import std.traits : isArray, isNarrowString;
import std.traits : isNarrowString;
Copy link
Member

Choose a reason for hiding this comment

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

Please remove the unneeded imports.

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
}
}

import std.traits : isIterable;
Copy link
Member

Choose a reason for hiding this comment

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

Maybe the self-important template idiom could be used here to avoid the top level import.

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's better wait for https://github.com/dlang/DIPs/blob/master/DIPs/DIP1005.md and its result / decision.

{
static assert(false, "Cannot transform range of type " ~ ArrT.stringof ~ " into a AliasSeq.");
}
static foreach (size_t i, el; iter.array)
Copy link
Member

Choose a reason for hiding this comment

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

I'm sure @UplinkCoder would know.

}
}

@safe unittest
Copy link
Member

Choose a reason for hiding this comment

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

It could stand to have a few more unittests testing different types of iterables.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are already quite a few existing that cover the range types, did have anything specific in mind?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. Specifically, infinite ranges. I believe isIterable will let those through, because all it checks is:

is(typeof({ foreach (elem; T.init) {} }))

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, infinite ranges were allowed with the previous implementation as well but obviously that's very bad. Done

@JackStouffer
Copy link
Contributor

Do we have any numbers on the slowness of static foreach vs recursive templates?

@wilzbach
Copy link
Contributor

Ping @John-Colvin

std/meta.d Outdated

/**
* Converts an input range `range` to an alias sequence.
* Converts any foreach-iterable (e.g. an input range) $(D range) to an alias sequence.
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume you accidentally converted the backticks back to $(D?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Must have a been a mistake when rebasing. Also, it should have been iter anyway

std/meta.d Outdated
}
}

import std.traits : isIterable;
Copy link
Contributor

Choose a reason for hiding this comment

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

Imports go at the top of the file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only existing top-level import in the file was not at the top, so I tried to stay in keeping. I will move both.

@MetaLang
Copy link
Member

MetaLang commented Apr 4, 2018

I took the liberty of adding a Params and Returns section in the documentation, as well as correcting a small typo (any foreach-iterable -> any foreach-iterable entity).

@wilzbach
Copy link
Contributor

wilzbach commented Apr 4, 2018

I think you added whitespace with this:

Check for trailing whitespace
grep -nr '[[:blank:]]$' etc std ; test $? -eq 1
std/meta.d:1126: * 
std/meta.d:1128: *     iter = the entity to convert into an `AliasSeq`. It must be able to be able to be iterated over using 
posix.mak:547: recipe for target 'style_lint' failed

@MetaLang
Copy link
Member

MetaLang commented Apr 4, 2018

Hmm, yeah I did. Very annoying that the Github editor does that.

@wilzbach
Copy link
Contributor

wilzbach commented Apr 4, 2018

Looks like we are running into an ICE when building the docs - it's probably the same as recently seen in
https://issues.dlang.org/show_bug.cgi?id=18721

@wilzbach
Copy link
Contributor

wilzbach commented Apr 4, 2018

Oh and the persistent Win32 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 ...

@John-Colvin
Copy link
Contributor Author

John-Colvin commented Apr 4, 2018

@MetaLang seeing as iterable is both an adjective and a noun*, I would say foreach-iterable is also both. It's ok, I'm fine with it written either way :)

* or at least it's commonly used that way and this is english after all, inventing words is fine haha

@wilzbach do you know of a workaround for either of those, or will the PR have to wait for them both to be fixed?

@wilzbach
Copy link
Contributor

wilzbach commented Apr 4, 2018

@wilzbach do you know of a workaround for either of those

Well I tried to reduce and fix the ICE, but I came out with this (dlang/dmd#8128), not really a solution :/

or will the PR have to wait for them both to be fixed?

I don't think that OMF will ever be fixed. I even asked Walter once:

That's a limitation of the OMF object file format. Keep in mind that OMF was designed for 8 bit CPUs :-)
It's not really fixable without redesigning the OMF format.
...
If you're interested, the limit is on page 2 under "Indexed References" http://www.azillionmonkeys.com/qed/Omfg.pdf

AFAICT the "workaround" against the OMF maximum symbol limit was to build the unittests separately e.g.

phobos/win32.mak

Lines 420 to 424 in 307dd15

unittest : $(LIB)
$(DMD) $(UDFLAGS) -L/co -c -ofunittest1.obj $(SRC_STD_1)
$(DMD) $(UDFLAGS) -L/co -c -ofunittest2.obj $(SRC_STD_RANGE)
$(DMD) $(UDFLAGS) -L/co -c -ofunittest2a.obj $(SRC_STD_2a)
$(DMD) $(UDFLAGS) -L/co -c -ofunittest3.obj $(SRC_STD_3)

Now, I'm not sure whether this is possible, but in theory the same could be done with phobos.lib

phobos/win32.mak

Lines 397 to 398 in 307dd15

$(DMD) -lib -of$(LIB) -Xfphobos.json $(DFLAGS) $(SRC_TO_COMPILE) \
$(ZLIB) $(DRUNTIMELIB)

So I think this could work:

	$(DMD) $(DFLAGS) -L/co -c  -oflib1.obj $(SRC_STD_1)
	$(DMD) $(DFLAGS) -L/co -c  -oflib2.obj $(SRC_STD_RANGE)
	$(DMD) $(DFLAGS) -L/co -c  -oflib3.obj $(SRC_STD_2a)
....

	$(DMD) $(DFLAGS) -L/co  unittest.d lib1.obj lib2.obj ...\
		$(ZLIB) $(DRUNTIMELIB)

(I don't use Windows either)

@wilzbach wilzbach force-pushed the improve_aliasSeq branch from 329cd6e to 4bfcd20 Compare May 9, 2019 16:26
@wilzbach
Copy link
Contributor

wilzbach commented May 9, 2019

(rebased)

@dlang-bot dlang-bot merged commit b83488e into dlang:master May 9, 2019
@John-Colvin
Copy link
Contributor Author

Well this is a PR I'd completely forgotten about! Nice to see it merged.

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.

6 participants