Skip to content
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

PhantomData is incomprehensible #22914

Closed
kornelski opened this issue Mar 1, 2015 · 10 comments · Fixed by #23925
Closed

PhantomData is incomprehensible #22914

kornelski opened this issue Mar 1, 2015 · 10 comments · Fixed by #23925

Comments

@kornelski
Copy link
Contributor

I need to give a Rust slice to a C API that will return an opaque handle (that actually contains a pointer to the slice), and the slice must outlive the handle.

rustc nicely suggested using PhantomData for this, but the description of phantom data (and its RFC) for me is so far removed from my mental model/terminology of the problem, that it sounds like git man pages to me.

  • "…tell the compiler about fake fields" — fake field doesn't sound like a thing I want to create. I'm not sure if a fake field is an actual Rust concept. I'm hoping it's a different way of saying a "pointer that Rust isn't keeping track of".
  • "inform the compiler that one or more instances of the type T could be dropped" — but does it actually drop anything? I want to prevent value from being dropped, so this confuses me.

The RFC is even worse, since it uses type variance terminology which is so confusing, that the most comprehensible description of them on Wikipedia is a 3D cube!

3d variance

@huonw
Copy link
Member

huonw commented Mar 1, 2015

PhantomData<T> allows you to describe that a type acts as if it stores a value of type T, e.g. maybe one is having to use opaque pointers or otherwise disguise the fact that there is a T contained in the value, or need to have a lifetime without having an actual & reference to attach it to. This is what is meant by "fake field": a PhantomData field doesn't actually store any data, but it behaves as if it does.

If you have a lifetime, and the type is acting like a reference, then PhantomData<&'a ...> (or PhantomData<&'a mut ...>) is the recommended approach. It's hard to be more specific without knowing your exact use-case, though.


In any case, the major motivation for PhantomData is to avoiding having to think in terms of co*variance, and instead just think of what the intended "storage" of a type is. The RFC is meant to serve as a technical reference to describe the behaviour unambiguously. I definitely agree that the current docs are not as helpful as they could be.

@kornelski
Copy link
Contributor Author

I see you've used lifetime as part of PhantomData's type. In my code I've used _marker: &'a std::marker::PhantomData<[u8]> and got confusing error messages. That bit in the documentation would help a lot! (just saying T is very unhelpful)

BTW: the first paragraph in your comment is already clearer to me than the documentation :)

@mdinger
Copy link
Contributor

mdinger commented Mar 1, 2015

The rustbyexample example seems relevant. A previous example was referenced at the mozilla research blog though I think rustbyexample is clearer. Note that the syntax of this example has changed recently. That PhantomData didn't used to be required.

If indeed what you need is something similar, you should flag it on rustbyexample for a more practical example.

@huonw I was only aware of using phantom types in for use cases like unit system manipulation and such. If you can provide the gist of what other things they can be used for I can probably shoehorn it into an rustbyexample example(s) (there's IRC if I get stuck). Though I don't know when I'd get to it.

@huonw
Copy link
Member

huonw commented Mar 1, 2015

@mdinger PhantomData is designed as a low-level building block to enable certain types of unsafe code to be written safely. The relationship to phantom types (as used for dimensional analysis etc.) is the name (almost-coincidence) and the fact that the language doesn't allow type parameters to be left completely unused (meaning a phantom type has to be mentioned, e.g, in PhantomData, to let the code compile).

Almost instances of phantom types for dimensional analysis won't care about the precise variance (unlike unsafe/low-level code) and so just need to make the compiler shut up. :)

@huonw
Copy link
Member

huonw commented Mar 1, 2015

@pornel great that you've made progress!

@mdinger
Copy link
Contributor

mdinger commented Mar 1, 2015

Okay. The distinction between them is definitely unclear then too (in the docs).

@bluss
Copy link
Member

bluss commented Mar 2, 2015

If it's just to make the compiler shut up, then it's a good indication that the old default was better (not needing PhantomData for most unused type parameters).

@alexchandel
Copy link

@pornel I sympathize. PhantomData and PhantomFn are Byzantine to me as well, and I'm hitting several issues in rlibc because of them.

@kornelski
Copy link
Contributor Author

@bluss That bit me, because unused parameter did absolutely nothing, even when I used a parameter with the same name a method. I don't mind having a marker, I just needed to learn how to use it.

@huonw
Copy link
Member

huonw commented Mar 2, 2015

If it's just to make the compiler shut up, then it's a good indication that the old default was better (not needing PhantomData for most unused type parameters).

To be clear, it is just the use of 'unused' type parameters for dimensional analysis/tagging where the details of the precise PhantomData used aren't so important. It is extremely important for data structures building on unsafe (or otherwise not using their lifetime/type parameters directly internally) to get their PhantomData uses correct, as they are actually informing the compiler of information necessary for safety. There has been a regular stream of bugs/problems discovered in types in this repo due to the old default not helping with unsafe code. (I imagine that many external libs with unsafe data structures have had to insert PhantomData's since the change... meaning they were likely incorrect too.)

steveklabnik added a commit to steveklabnik/rust that referenced this issue Apr 1, 2015
Manishearth added a commit to Manishearth/rust that referenced this issue Apr 1, 2015
Fixes rust-lang#22914

Said issue was mostly fixed, as there wasn't any examples when it was initially posted. This is mostly just some re-wording of some things and some cleanup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants