Phobos 3 Discussion Notes - 02-01-2024

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sun Feb 4 21:32:15 UTC 2024


On Sunday, February 4, 2024 8:04:00 AM MST Paul Backus via Digitalmars-d 
wrote:
> On Sunday, 4 February 2024 at 09:30:58 UTC, Jonathan M Davis
>
> wrote:
> > The main thing that it needs IMHO is going through it and
> > making sure that it's doing the right thing for each trait and
> > that the exact set of traits that it has is really what we
> > want, since right now, several of them are doing the wrong
> > thing (e.g. treating enum as if it were its base type with
> > stuff like isIntegral, isNumeric, etc., which is a source of
> > bugs).
>
> I have bad news for you. This behavior is not the fault of
> std.traits, but is actually baked into the language itself. For
>
> example, the spec for __traits(isIntegral) says:
> > The integral types are: byte, ubyte, short, ushort, int, uint,
> > long, ulong, cent, ucent, bool, char, wchar, dchar, vectors of
> > integral types, and enums with an integral base type.
>
> https://dlang.org/spec/traits.html#isIntegral
>
> Maybe we can clean this up in a new language edition, but as long
> as this is how the underlying __traits work, std.traits should
> work the same way.

std.traits doesn't actually rely on that. It does its own checks for enum,
and it does so inconsistently (e.g. isSomeString doesn't allow enums, and it
was a source of bugs and frustration when it did years ago, because it meant
that range-based code was accepting enums with a base type of string and
then not working, because they aren't actually ranges). Traits and template
constraints in general need to be checking for either an exact list of types
or for whether the provided type has a particular set of capabilities.
Allowing implicit conversions is almost always a source of bugs. So, while
it should obviously be possible to check for implicit conversions where
appropriate, IMHO, it's a big mistake for Phobos to encourage it or make it
the easy the default. It should not be necessary to put !is(T == enum) all
over the place in code to stop enums or alias this from making it into a
function and then not behaving properly, because the type wasn't actually
converted, and the fact that std.traits is not principled about that is one
of its biggest problems IMHO - though as with a number of things that need
to be fixed in Phobos, they're mistakes that really only become clear after
more experience with what we attempted the first time around.

So, regardless of what __traits is doing, I will argue quite strongly that
std.traits should not be treating anything as its base type unless that's
truly what makes sense for that particular trait, and if __traits isn't
doing that, then it should probably fixed in a future edition as well. But
ultimately, __traits is a building block for other traits, so what
std.traits does does not have to be the same thing, though having the same
name in __traits and std.traits do something different from each other is
something that should probably be avoided. So, I agree that having
__traits(isIntegral, T) accept enums and std.traits.isIntegral reject them
is not a good idea. But my solution at that point is to not call the trait
in std.traits isIntegral but rather given a distinct name.

- Jonathan M Davis





More information about the Digitalmars-d mailing list