eddyb centril : thinking about fields not being additive: if we wound up defaulting to *invariant* if a type is not used (which I think is what I would want), that has the nice-for-semver property that adding fields only makes subtype *more* accepting (though that's not normally the case). Probably it's "fine" to just do the default that way and thus
eliminate phantom data unless you want to establish variance etc. (There is also the matter of dropck and cycles; I think we would consider `T` to be "non-owning" by default? But probably it's best to go with the most conservative route, just as with variance. I doubt it matters much in practice.)
eddyb
I think it'll ruin anything with lifetimes in it... but if it's just some ZST or boring newtype you don't *really* need lifetimes
centril
nmatsakis: the nice thing about covariance is that struct PhantomData<T: ?Sized>; is now not using a lang item but is just library code
so I think it is least surprising
nmatsakis
eddyb: basically every time that I find phantom-data annoying,
it's because of some "token" type parameter T
that more defines behavior than carries data
in which case phantom data doesn't make any logical sense
eddyb
ye
nmatsakis
I think I would *also* like it if we could not create the marker explicitly
e.g. we originally envisioned this:
struct Foo<T> { phantom T, ... }
not a "real" field
that would perhaps *also* be nice, to make phantomdata ergonomic for the cases where you need it
eddyb
nmatsakis: I prefer something that applies generally to ZSTs :P
nmatsakis
eddyb: I .. huh. Surely not *all* ZSTs
i.e., you may not be able to create one
I guess you mean "all ZSTs that are public"
eddyb
nmatsakis: sorry I meant
public constructors yeah
nmatsakis
like, singleton unit variants or whatever that's called
struct Foo;
yeah that .. might be nice
eddyb
trees of product types with public constructors
nmatsakis
it seems kind of surprising to me; what other use cases are there?
centril
invariance by default would actually make struct Id<S, T>; instead of struct Id<S, T>(PhantomData<(*mut S, *mut T)>); which is nice
eddyb
nmatsakis: not sure if you saw the discussion from yesterday
you could even write _ instead of () :P
nmatsakis
centril: phantom data would still be a lang item, btw
it's not just about variance
it's also about dropck
eddyb
and auto traits, maybe?
nmatsakis
yes
centril
nmatsakis: oh right
nmatsakis
eddyb: I saw something, but I forget. I guess you were saying some sort of expression?
centril: though I suppose ... hmm .. if we said that any unused type parameter is basically "as if you own it"
in that case, phantom data *is* just a library type
and any `struct Foo<T>` would act the same
`struct Foo<T>;`
(is that true?)
I may be confusing myself
centril
think so
nmatsakis
anyway, I'm in favor of something along these lines; I find phantom data "as is" to be annoying often enough
there's something that feels funny about what I just said
I think it is this:
eddyb
wait
nmatsakis
well, no I guess it is correct
eddyb
type PhantomData<T> = Option<(T, !)>;
problem solved lmao
(that's a ZST)
centril
eddyb: what the hell =P
eddyb
(well, you'd want a newtype but still)
nmatsakis
I guess if we assume that `T` means you own it
then it would be *covariant*
eddyb
nmatsakis: the real answer was Void/! enum optimizations all along!
nmatsakis
that is, if we assumed a `struct Foo<T> { PhantomData<T> }``
eddyb: maybe, I guess it depends if the compiler is allowed to see
eddyb
we just didn't connect the dots
nmatsakis
that `(T, !)` means you never *actually* have a `T`
eddyb
you mean to avoid triggering the infinite size error?
centril
eddyb: that works for defining PhantomData, but doesn't solve the ergonomics of getting to elide PhantomData<T> in struct Foo<T>;
eddyb
yeah I know I just found it really funny
centril
you can get half way by allowing struct literals to call Default::default()
eddyb
that you can now get a ZST which includes a non-zero type
centril
eddyb: yea it was pretty hilarious
nmatsakis
eddyb: no I mean like, you could *imagine* our "does it own a T" analysis saying that because `(T, !)` is uninhabited, it doesn't count as owning a T (and hence permit cycles in the type of `T`)
I'd sort of rather we're not that smart though...
centril
nmatsakis: yeah I agree, that is too smart
eddyb
nmatsakis: yeah I didn't consider the cycle problem
Jesin joined the channel
nmatsakis
note: if we removed contravariance :) then covariance becomes the proper "zero" for the lattice
er, starting point
bottom I guess
eddyb
we can't remove contravariance >:P
nmatsakis
I know :
=)
(I don't think we have to anymore anyway)
eddyb
wait so
[T; 0] worked since forever
with the caveat of using T's alignment
nmatsakis
arguably `[T; 0]` could have alignment 1
nox
centril: Don't be sorry (didn't highlight me so I didn't see your answer).
nmatsakis
(right?)
nox
(You can also highlight me with "baguette", btw.)
centril
nmatsakis: what do you think of struct Foo { bla: () } let myfoo = Foo {}; as sugar for let myfoo = Foo { bla: Default::default() }; ?
nmatsakis
seems a bit surprising to me
why would assigning from `()` be "default"?
I guess I prefer `bla: _` or `bla: ..` as generalizing to that
incidentically, eddyb, that would give you what you wanted ?
(Without being specific to ZSTs...)
centril
nmatsakis: the rule being that the default is used for all fields omitted
nmatsakis
oh I missed that
I like that evne less :)
if I add some new field (e.g., `bla: u32`)
there is no paricular reason to think that `0` is the value I wanted for it
I would be ok with `Foo { .. }` meaning "use Default for all remaining fields"
or something like that
centril
nmatsakis: so we'd want breakage here?
nmatsakis
I would
I rely on things like that all the time
centril
nmatsakis: Foo {..} seems totally fine to me
nmatsakis
to help me refactor
I tend to write my code for maximum compile-time breakage :)