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
Revive pull request #1348: "Issue 9882 - Implement a "tee" style InputRange... #1965
Conversation
template tee(alias func, Flag!"pipeOnFront" pipeOnFront = No.pipeOnFront) | ||
if (is(typeof(unaryFun!func))) | ||
{ | ||
auto tee(Range)(Range inputRange) if (isInputRange!(Range)) |
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.
nitpick: isInputRange!Range
I'd change the commit message to describe what is changed rather than discuss GitHub processes. Also the Pull Request description should say what this is for. |
{ | ||
private Range _input; | ||
|
||
this(Range 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.
This constructor is basically dead code.
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.
Fixed.
The result should propagate length. Perhaps it should also propagate bidirectionality and random access (and slicing?), with As for the idea itself, as I've stated before, I personally don't want this in Phobos because it encourages mixing functional-style and imperative-style code. edit: It looks like the commit should have retained the original author as an act of courtesy. |
"It looks like the commit should have retained the original author as an act of courtesy." Whoops, that was completely unintended. Is there a way to fix that? |
The easiest way would be to simply checkout the relevant branch on the author's fork, then rebasing that onto a new branch of your own, branched off |
@eco Edited with the original commit message. @JakobOvrum Is it possible to make a new commit with the updated author? I originally checked out the author's branch, cherry-picked it into a new branch, then made a few changes and rebased, which squashed the original commit with them as the author... I think. |
You'll want to remake the commit that introduces the relevant changes. The easiest way to do that is with |
git commit --amend --author sounds a lot simpler. I'll just do that with a commit that removes the outer template. |
…o that a function can be called during a chain of InputRanges."
As I said, |
I am not comfortable enough with git that I'm confident I wouldn't mess anything up. |
Removed outer template and the redundant constructor. As for tee's usefulness, it is intended to aid in debugging range code. It is somewhat dirty inserting imperative code into a mostly-functional range chain, but we can also use debug in pure functions for debugging. This has an advantage over std.algorithm.map in that the user can choose whether to call the lambda function when front is accessed, or only on popFront. |
The proposed documentation does not state that this is intended for debug code. With debug statements in pure functions, it is also obvious at the call site that the code is debug code, which is not the case for |
…CS chains, and that the default behaviour is to call func on popFront
I have modified the documentation to make it clear that tee is useful for debugging. |
…vailable statically, make it available statically in the result as well. Change pipeOnFront back to pipeOnPop because _input may have back and popBack.
Implying tee can't be used for things "other" than debug? If this is really the case, then |
assert(equal(newValues2, values)); | ||
|
||
int count = 0; | ||
auto newValues3 = filter!(a => a < 10)(values) |
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 should UFCS from the start:
auto newValues3 = values
.filter!(a => a < 10)()
.tee!(a => count++)()
.map!(a => a + 1)()
.filter!(a => a < 10)();
Propagating random access with I you can propagate RA safely iff |
One of the issues I am seeing is this pattern of int sentinel;
auto range = tee!(++sentinel)( ... );
assert(range.equal([...]);
assert(sentinel = ...); I see this as a problem, because I'd recommend you use a piece of code that will un-conditionally walk you range, and then test the sentinel. I kind of wish we had a That, or just: bool b = r.equal([...]); //Side effect
assert (b); //Test result |
I already stated that I don't think it's appropriate for other purposes (or for debug purposes for that matter). |
Ah... I failed to correctly read the totality of that post. Apologies. I think your "In particular, I think how tee is intended for extra side-effects, masked as functional code, hurts readability." is relevant to the comment I made regarding "I see this as a problem, because sentinel will only be modified if the range is actually "walked"." |
I don't see it as an issue because you can also call |
Right, but you can't iterate with
I'd confused with that specific name, since I'd understand it as mutating the elements themselves.
Agreed. That's already done though. |
Agreed with @JakobOvrum. I'm worried about the side-effect nature of the way your are supposed to use this, and I'm incredibly worried about what that means when I do think the |
I'd like it if someone could comment on my use of DDOC. I'm not familiar with it at all, and I don't know if I'm using it correctly. Also above Andrei suggest the following:
My response was:
Can somebody comment on this? |
I actually think what Andrei proposes is fundamentally wrong approach. We do have a problem of unspecified standard range consumption and this proposal is an attempt to hide it via hack. There was recently a similar discussion in one of other pull requests I can't spot right now :( I don't know how to better proceed with it - there seems to be no agreement between @WalterBright and @andralex on this topic and keeping it as permissive as it is creates collateral damage in Phobos. |
Perhaps we should leave it for now, then, and I can make further pull requests in the future once everyone can agree on an answer. |
I'm not sure I understand the context of @andralex 's proposal. What advantage does checking the flag 3 times in |
I think his desire was to have the input "tee'd" whether the user accesses front first, empty, or popFront. I did not really understand at the time either, but it seems this is in the context of trying to hash out what the conventions for range semantics should be (there was a thread on the newsgroup about it some time ago). |
…ide implementation details from users.
@quickfur problem is that currently one does not know what range methods will be called each iteration cycle and how many times each. It is unspecified which forces all kinds of weird hacks when you try to implement something like "do this exactly once for each range element". @MetaLang meh I am afraid if we won't do nothing it will just get lost again. I don't know what to do :( |
Ah, I see. So basically if you chain |
Bah, looks like I'm talking nonsense again: |
It will do so in either front or popFront, configurable by the user with pipeOnPop. |
Ah, i see. That makes sense. I'm inclined to say this is good to merge. I don't agree with Andrei that we should check the flag in all 3 places, especially in |
Then what are we waiting for? @Dicebot @monarchdodra |
Ok, lets do it and see how badly it breaks :) |
Auto-merge toggled on |
Blergh. I bet later we'll consider |
I don't think the breakage will be very bad, if any at all, since it returns a non-forward input range, and there are only a limited number of things you can do with an input range. |
Revive pull request #1348: "Issue 9882 - Implement a "tee" style InputRange...
I agree it is a terrible name but I want this functionality in Phobos and tired of endless bikeshedding. |
I didn't get a chance to squash my commits before the merge. Does a squash after merge still work? |
It's too late now. While in theory you can modify history in But in the end unsquashed commits don't matter, since git tracks the branching structure of the commits, so |
Righto. Thanks. |
The functionality is the problem. |
.tee!(a => writefln("pre-map: %d", a)) | ||
.map!(a => a + 1) | ||
.tee!(a => writefln("post-map: %d", a)) | ||
.filter!(a => a < 10); |
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 unittest is producing stdout output. This is especially bad since the unittest is un-documented, so completely useless.
@MetaLang : Can it be re-written in a way that does not write to stdout, or does it conditionally? Could you write to an output range instead, maybe? By printing to an output range, you can also assert the correct output of your range.
In any case, the printing is disruptive to unit-testing:
https://auto-tester.puremagic.com/pull.ghtml?projectid=1&runid=1127154
@monarchdodra Will do. I'll make another pull request after work. |
Pull request: #2480 |
...so that a function can be called during a chain of InputRanges."