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
[WIP] Proof of concept for versioning the standard library #8309
base: master
Are you sure you want to change the base?
Conversation
Thanks for your pull request, @andralex! Bugzilla references
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 + phobos#8309" |
std/v2/range/primitives.d
Outdated
module std.v2.range.primitives; | ||
|
||
/** | ||
@@@TODO@@@ Publicly imported names across modules should copy or link those |
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.
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.
@adamdruppe that's close. How easy would it be to modify dpldocs to:
- actually link to the individual names imported?
- maybe copy the entire documentation?
- maybe make the documentation available as a macro for subsequent use?
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.
All pretty easy, I just never got around to it (I personally kinda hate selective imports. They're .... really weird when you get into them. I prefer static imports. But since I don't personally use it and there's been no user demand this just never became enough of a priority to actually do. But it'd prolly only take an hour or two.)
std/v2/algorithm/comparison.d
Outdated
import v1 = std.algorithm.comparison; | ||
|
||
/** | ||
[@@@TODO@@@ Documentation specific for version 2. It should be appended to the default as |
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 is relatively easy to do in a doc generator, but most aliases probably don't want this behavior. I think if I was going to do it in the adrdox I'd do it with antoher magic macro like
/++
$(SHOW_ALIAS_DOCS)
Supplemental stuff here.
+/
And the magic macro there is expanded to be a copy of the thing it is an alias of or something like that.
I'm not sure I love it though, just plain linking is probably a better experience more often than not.
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.
Yah, I too think a sort of directed choice is best and most flexible.
std/algorithm/comparison.d
Outdated
{ | ||
static foreach (r; rs[1 .. $]) | ||
{ | ||
if (r.empty || !binaryFun!pred(rs[0].front, r.front)) |
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.
binaryFun
with a string predicate imports a bunch of std
stuff (including std.range
). You need to migrate that as well.
Honestly, ANY functions that you use anywhere should be v2, which should then publicly import the v1 versions if unchanged. Otherwise, any time you want to change a function only for v2, you have to go through every possible usage of it anywhere and upgrade the machinery.
Note that this is kind of implied anyway, because a std.v2 of phobos is going to need to be just as usable as v1 of phobos. But the fact that this worked and pulled in definitions from v1 without explicitly requesting it means this mechanism is prone to subtle v1/v2 mismatch (no pun intended) errors.
I almost think the canon
template should be in its own file that isn't accidentally importing v1 stuff.
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.
Thanks for taking a look!
binaryFun
with a string predicate imports a bunch ofstd
stuff (includingstd.range
). You need to migrate that as well.
Interesting. I'm not so sure. If std.functional.binaryFun
version 1 works as needed to implement v2's mismatch
then mismatch
is free to just use it without migrating it at all. It's a trivial case of code reuse.
Honestly, ANY functions that you use anywhere should be v2, which should then publicly import the v1 versions if unchanged. Otherwise, any time you want to change a function only for v2, you have to go through every possible usage of it anywhere and upgrade the machinery.
I'm unclear on why this is necessary. Clearly in the long run all symbols are migrated, but during the alpha version of v2 implementations therein should be free to use parts of v1 privately wherever appropriate.
Note that this is kind of implied anyway, because a std.v2 of phobos is going to need to be just as usable as v1 of phobos. But the fact that this worked and pulled in definitions from v1 without explicitly requesting it means this mechanism is prone to subtle v1/v2 mismatch (no pun intended) errors.
I think this is a liability only if said v1 artifacts are misused, i.e. not used according to their spec.
I almost think the
canon
template should be in its own file that isn't accidentally importing v1 stuff.
That would probably be a nice option in the future.
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.
Interesting. I'm not so sure. If
std.functional.binaryFun
version 1 works as needed to implement v2'smismatch
thenmismatch
is free to just use it without migrating it at all. It's a trivial case of code reuse.
It's not a trivial problem. It will result in subtle WTF moments e.g. an alternate form of your unittest:
auto s1 = ["öabc"], s2 = ["üabc"];
auto a = mismatch!((a, b) => a.front == b.front);
assert(a[0].empty && a[1].empty); // all start with the same byte
auto b = mismatch!"a.front == b.front";
assert(a[0] == s1 && a[1] == s2); // but if using string lambdas, autodecoding is back!
For mismatch
, this is probably not going to show up very often, because it has to be a range of ranges AND you must use range functions/algorithms inside your lambda AND it must be a string lambda. But I heavily dislike the subtle inclusion of v1 stuff in corner cases.
Ways to fix:
- Fix the string lambda mechanism of
binaryFun
so it doesn't import ANY niceties if in v2 mode. You want string lambdas? They have to be simple, or use v1 functions. - Remove string lambda support completely from v2. stirng lambdas are kind of obsolete anyway
- Fix the code so
binaryFun
imports v2 versions of all those libraries (and fix all those libraries not to use autodecode). That makes this PR significantly bigger and more complex.
I think this is a liability only if said v1 artifacts are misused, i.e. not used according to their spec.
I think you are headed for a lot of pain if you don't ensure all dependencies go through a v2 gate, even if it's an alias to the v1 version. You did this with allSatisfy
and isInputRange
, I'm not sure why you would leave out binaryFun
.
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.
Further note, tuple
and Tuple
should be v2 as well.
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.
Excellent point, thanks. Incidentally I thought (before realizing this issue) that we should repudiate string lambdas as we have reasonably terse and much more principled lambdas now.
It looks like transitive dependencies must be carefully analyzed to figure out what's what.
Any issues you foresee with Tuple
and tuple
related to unexpected incompatibilities?
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 stdv2.typecons going to exist? If it is, then either it has the same stuff or modified stuff. Having to know this for reviews, usage, etc. is just a pain. I'd rather just everything that is v2-focused import v2 stuff ONLY, unless it is exposing v1 stuff explicitly (i.e. publicly importing symbols, or using the v1 canon
template).
If stdv2.typecons is not going to exist, then it's not ambiguous, and possibly OK.
Whatever happens to this, I just want to say: a real attempt is worth 10x more than just discussing forever. It's 's trying to move things forward. Perfection is only found in the platonic universe, once brought out in the physical world, imperfections will always be noticeable. Brace yourself, v2 is coming |
| std/v2/range/primitives.d(15:24)[warn]: A public function needs to contain a |
On Mon, Nov 01, 2021 at 06:41:53PM -0700, Andrei Alexandrescu wrote:
> `binaryFun` with a string predicate imports a bunch of `std` stuff (including `std.range`). You need to migrate that as well.
Interesting. I'm not so sure. If `std.functional.binaryFun` version 1 works as needed to implement v2's `mismatch` then `mismatch` is free to just use it without migrating it at all. It's a trivial case of code reuse.
This means user predicates will exhibit behavior inconsistent with the
rest of the library.
My view is binaryFun ought to simply be removed. It adds only
complication coming significantly short of pulling its weight. v2 is a
good opportunity to remove this kind of bloated complexity.
But if it is present, surely the functions you call from inside it ought
to behave similarly to everything else in std.v2?
|
std/v2alpha/algorithm/comparison.d
Outdated
@@ -0,0 +1,24 @@ | |||
module std.v2alpha.algorithm.comparison; |
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 suggest std2
instead of std.v2
. v2
should not be a sub-package of std
version 1.
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.
Kinda makes sense. It would be a different story if we had this in the beginning, like if it already was std.v1 etc and now std.v2 etc.
General question arises (excuse me if this is already answered in the forums):
Would these be side by side?
Will you be able to selectively import stuff from std while still using std2?
import std;
import std2 : awesome;
import std2;
import std : awesome;
No conflict because the selective import always wins?
std/v2alpha/meta.d
Outdated
|
||
/** | ||
On an individual public import, it would be very helpful if the documentation | ||
for that symbol were copied here (or available as a macro). |
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.
For now it can be simply linked to with the $(LINK ...)
macro.
std/v2alpha/range/primitives.d
Outdated
/** | ||
@@@TODO@@@ This function redefines `front` for v2, meaning its documentation | ||
will override the documentation of `front` found in v1. The difference is of | ||
course that the new `front` does not autodecode. |
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.
Adding a link to the v1 documentation makes it easier for people to see what's been updated.
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.
Very nice! Just change it to std2
and it's good to go.
stdv2 should be on the same level as std so the directory structure will be the same |
std/v2alpha/range/primitives.d
Outdated
{ | ||
assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof); | ||
a = a[1 .. $]; | ||
} |
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.
what about
private deprecated void popFrontString(scope ref string a) {
// auto decode impl
}
void popFront(T)(scope ref inout(T)[] a) {
static assert(!is(T[] == void[]), T.stringof ~ "[] not a support range");
static if(is(T == string)) {
popFrontString(a);
} else {
a = a[1 .. $];
}
}
No need for std2, you should get a deprecation message ... move on
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.
No, we don't want to remove strings as 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.
after the deprecation phase we would remove everything but the first static assert and the a = a[1 .. $];
strings should still work, only without autodecoding.
What did I miss?
5c6d9ba
to
a649600
Compare
ae0f568
to
baa968f
Compare
Another bug in the compiler revealed by unittests: ../dmd/generated/linux/release/64/dmd -conf= -I../druntime/import -w -de -preview=dip1000 -preview=dtorfields -preview=fieldwise -m64 -fPIC -O -release -defaultlib= -debuglib= -L-lpthread -L-lm -betterC -unittest -run generated/linux/release/64/betterctests/std_algorithm_comparison.d issues the nonsensical error:
The line is bogus and the error is bogus. |
0911a78
to
1db3023
Compare
Affirmative. It's a bug I'll submit in a few hours that needs to be fixed before this PR can be merged. |
Good. But it's a red flag that an implementation detail like |
…ake std2xalpha.range.iteration.cache and its Bidir variant work
a94b148
to
b4ef8b4
Compare
I think you should stop adding new functions and get what you have already made merged first. That way others can also begin porting the functions. |
I wish things worked out that way, and that was my hope starting this. However, there are a couple of problems that make that impossible. Loosely in decreasing order of importance:
So... not a simple or quick process. |
Just disable the docs for now. It's going to require future PRs anyway before v2 is ready for any serious use, and we're definitely not going to worry about breaking the code of any experimenters. So no need to do it all in one monolith PR. |
How do you mean that? |
Anyone who knows a bit about docs, what would be the best way to hide the documentation of V2 for now without affecting V1? |
This PR introduces a very limited v2 of the standard under the name
std.v2
. There are only very few artifacts in there. Essentially, this PR just showcases howmismatch
can be versioned so as to accommodate autodecoding in v1 and no autodecoding in v2.To that end, v2 supports the following artifacts:
std.v2.range.primitives.empty
,std.v2.range.primitives.front
,std.v2.range.primitives.popFront
,std.v2.range.primitives.isInputRange
,std.v2.meta.allSatisfy
. Some of these are simply pulled from v1, others are redefined with new meaning.The characteristics of this approach:
version
/static if
hell.git cherry-pick
ing across versions hell.The main challenges are:
import
must be improved. Right now themixin
imports are rather awkward.