-
Notifications
You must be signed in to change notification settings - Fork 542
Add exercise for doubly linked lists with unsafe #653
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
Conversation
Each node in a doubly linked list contains data and pointers to the next | ||
and previous node, if they exist. | ||
|
||
New nodes can be efficiently added at any point in the list, if one already has |
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.
It may be worth mentioning practical applications, such as the dancing links algorithm.
This is a really great start for an exercise! Thanks, @Emerentius! There are a lot of small points, and a bit of architectural reshuffling, but the core is strong, and this will be a really useful exercise for advanced students. Agree that you need to rename this. Suggest just "doubly-linked-list". |
0e12825
to
367ddb2
Compare
You've caught me at an inopportune moment: I'm about to head on vacation, so can't promise to review this within the next two weeks or so. I will comment that while this exercise requires a fair amount of implementation, at least per the examples, it's not the most verbose exercise in the track: $ fd example.rs --exec wc -l {} \; | sort -nr | head -n3
Thu Sep 13 09:46:04 DST 2018
342 exercises/poker/example.rs
245 exercises/react/example.rs
187 exercises/decimal/example.rs Therefore, I wouldn't worry too much about the length. |
No rush. I still have to figure out what the deal with dropck is and overhaul the tests so that they have a clear thread. |
The reason Travis is failing is that the README is other than it expects. Try regenerating that? |
Of interest to the cursor implementation: https://github.com/4e554c4c/rfcs/blob/cursors/text/0000-linked-list-cursors.md Are you still working on this, @Emerentius? I still think this will be a cool addition to the track, but I haven't seen much movement recently. |
There's one safety related issue that I have been blocked on because I don't yet understand it: the interaction with dropck. I haven't yet been able to understand what problems can potentially arise from not doing so and whether the danger is always present or whether you have to opt-in to it somehow. The nomicon doesn't have an example demonstrating the unsafety. This issue says that the chapter is outdated anyway and I don't know where the authoritative definition is located right now. |
My understanding is that the dropck concern is not relevant to this exercise, because we don't have any structs which own raw pointers. We likewise don't require or request that students implement structs which do. I'd love to get someone experienced with unsafe code to give a firm answer, but I don't have contact with many people who are experienced with unsafe code. @petertseng do you have thoughts on this? In conclusion: I'm about 80% confident that there is no dropck concern for this exercise, and therefore you should consider yourself unblocked. |
Doing some reading, I believe that I have a little better understanding:
If all of these points are correct, then we can officially declare that this issue is Out Of Scope for this PR. Our |
I will caution that I actually don't fit the description of "experienced with |
869eb8a
to
4e899ea
Compare
I can't reproduce the travis failure locally Edit: I found and fixed it after rebasing. The travis failure now is because of a race condition in the tests. |
c83bb99
to
9035272
Compare
@petertseng I've changed everything I wanted to. If anything major is amiss, I'm lacking the fresh perspective. If you could try your hand at it, that would be cool. |
I wanted to but I found myself unprepared to do |
After far too long, I've made the time to perform a student implementation of this exercise. You can find the sum of my efforts here. coriolinus@668e146 fixes some deprecation warnings; rustfmt made some additional changes which I assume are just style updates. This commit should probably be merged into this branch. I took notes as I went through and implemented this; the full file is here, but don't take any of the early stuff to heart: I was more or less just logging my thoughts as I went, and I ended up fixing a lot of the stuff the early notes complain about. The highlights/final form are as follows:
I apologize that it took me so long to get to this, but this really was the first opportunity I've had. I believe that these are the only items waiting before merge:
|
If there are no comments before then, I intend to do the following on Wednesday the 7th:
While this has become a low-velocity issue, it is in nobody's interest that it remain one. |
I also noticed, that the phase 1 tests start off with
|
otherwise use after free
simplify and slightly extend tests using this functionality
Outside the README, no mention of nodes is made anymore, only of positions.
This exercise is track-specific and there's therefore no equivalent in problem-specifications from which a version could be taken.
via cargo features
rename and group by their dependence on the steps in the README removed tests for pre-implemented methods added tests for remaining cursor methods add memory leakage tests
doc comment-ing pre_implemented module comment for PhantomData marker
by separating them into their own files there is no Cargo.toml key to do the same as passing --test-threads=1 This is easier than telling students to pass the argument and adapting the CI
Crashing drop affects everyone right from the start. Delay until step 4.
group tests that only push/pop at back, then tests working only at the front and only then mix
not needed for tests
all functions where the caller has to maintain invariants are marked unsafe and all unsafe blocks and impls are commented as to why they are safe. In the process of doing so, it became clear that most methods in NodePtrHelper and a few others were unsafe. Furthermore, many were only used once after previous refactorings. Those now obsolete abstractions were removed and the code refactored to minimize the amount of unsafe.
and regenerate README
I've done all the changes, rebased and regenerated the README. Adding the invariant documentation helped me clean up the example a lot. There were several functions that were unsafe but not marked as such. In your solution, I noticed that you implemented |
Hah, good; those extra tests would have helped me! That's a good tip, as well. I think this looks great. I'm still going to wait until Wednesday to merge, just to ensure that we've left enough time for other maintainer comments, but at this point, my intent is to merge on Wednesday. |
This PR isn't finished, but I'd like to get some feedback already. Would this be a good addition at all? Are any major design changes necessary?
This adds a new exercise that is specifically about the nitty gritty details of unsafe. There is a
linked-list
exercise inproblem-specifications
, but this is not supposed to be it (I will have to rename it).It's expanded in two ways:
O(1)
unsafe {}
Doubly linked lists are infamous for tripping up newcomers to Rust who choose it as their first trial project and are hit with the full force of the borrow checker before they had a chance to learn about it.
Because they are an owning collection, students will have to learn about how to manually manage memory via
Box::into_raw
andBox::from_raw
and expose a safe interface. Because it's an owning collection, it also touches onSend
,Sync
and covariance over the contained items (these should probably behind a feature flag). There's also some interaction with drop check, but I am yet to understand exactly what the rules are.I've tried to keep the exercise simple, yet not too far removed from actual use cases by including the cursor. Without it, you may as well use
VecDeque
. There aren't actually that many cases whereunsafe
needs to be explicitly written, but a lot of potential for use-after-free, double-free, accidental leaks, etc, if you don't manage the pointers correctly.Overall, it came out a little long. I'd love for the required code to be reduced to <200 lines.