FieldNames is roughly equivalent to std.traits' FieldNameTuple, and
FieldTypes is roughly equivalent to std.traits' Fields (which used to be
FieldTypeTuple).
The primary difference implementation-wise is that the phobos.sys.traits
versions require that the types that they're given be aggregate types.
For some reason, the std.traits versions accept any type and then try to
give a result that at least sort of make sense when they're given a type
which isn't an aggregate type (even though they really can't, because a
type which isn't an aggregate type has no fields, making any choice kind
of arbitrary).
For types which aren't aggregate types, Fields gives the type back in an
AliasSeq, and FieldNameTuple gives AliasSeq!"". Neither makes any sense
to me. I assume that it was done so that those traits could be used in
generic code and work with any type, but realistically, if you want to
do anything sane with them, you need to already have verified that
you're dealing with an aggregate type, since it's just going to be
error-prone to do stuff like Fields!int and then get AliasSeq!int back
as if it had a single field of type int (or FieldNameTuple!int and get
an empty string as the name). So, the phobos.sys.traits versions simply
require that you give them aggregate types to avoid that entire mess.
FieldNames evaluates to the names of the fields as strings. The "Tuple"
in the name of the std.traits version is an artifact from when AliasSeqs
were called TypeTuples, so I didn't keep that.
FieldTypes evaluates to the types for the fields. It's FieldTypes rather
than Fields for clarity, since it's not at all obvious what Fields is
supposed to give you (if I'd had to guess, I would have guessed the
symbols, not the types).
FieldSymbols is new. Its usefulness is questionable, since it does
almost exactly the same thing that tupleof does. However, I've included
it because of the subtle issues that you get with nested structs -
namely that tupleof includes a context pointer in its result, which you
probably don't want (though that obviously depends on what you're
doing), and FieldNames and FieldTypes don't include it (just like their
std.traits counterparts don't), so it seemed like it would make it less
error-prone to have FieldSymbols for the cases where symbols are needed.
The documentation explains (and the examples show) the difference
between FieldSymbols and tupleof so that the programmer can decide which
makes more sense for their particular use case.