The NaN of types (in D)
Q. Schroll
qs.il.paperinik at gmail.com
Mon Oct 12 19:57:02 UTC 2020
On Monday, 12 October 2020 at 15:10:55 UTC, Stefan Koch wrote:
> You cannot create a variable of type ø.
> ø myVar; is invalid.
> You cannot ø as a returnType or as a parameter type.
> So a functiondeclatation like ø fn(int x) or int fn(ø x) is
> invalid.
>
> But you can ask for it's size.
> ø.sizeof == 0.
> For it's members
> __traits(allMembers, ø) == []
> ....
> And I think that's all of the introspection I currently support.
>
> __traits(getAttributes) is currently not available anymore as I
> need to define, a type which can hold anything (and not just
> types) for that to work.
As I understand it, the NaN of types (call it NaT, not a type) is
only vaguely similar to NaN in the regard that is(NaT == NaT)
would return false.
NaT's only purpose is to be __type.init because __type.init is
needed. For that matter, __type.init could be int, but there are
reasons not to do that; the same as there are reasons not to make
double.init 0.0, but double.nan. Having a __type.init that, for
all intents and purposes is a type, i.e. __type.init binds to
type-parameters in templates, but whenever it bubbles up to the
point of an `is` expression or the point where the type is used,
it will be special cased so that to the user it appears as it
just isn't a type. In that way, it would be totally different
from a bottom type. A bottom type will always look like a type to
the user. Making __type.init be __bottom is on par with making it
int. To be honest, __type.init does not even need a name; it
could be referred to by `__type.init` similar to `typeof(null)`
hasn't a name. You could alias it, sure.
However, I'm not entirely convinced that making is(NaT == NaT)
return false is a good idea. It makes things complicated and
confuses the heck out of meta-programmers when debugging stuff.
Just make NaT a type. "Using" it computationally, i.e. getting
its .init, declaring a variable of it, make a function return
values from it, that would be an error because the type doesn't
actually exist.
(Mathematically speaking, the bottom type is the empty set. You
can ask if some potential element is in a type; for the bottom
type, the answer is no every time. But __type.init isn't a real
type. The question if something is an element of __type.init
makes no sense. In that regard, __type.init kind of is like an
element of the empty set: It does not exist! Still we can "let x
be an element of the empty set" and talk about x. But that x
cannot have a value.)
Because types must be resolved at compile-time (versus values
that are resolved at run-time), double's NaN has to be dealt with
in the running program. It would be great if double.init would be
NaN, but the magical compiler could keep that value from ever be
part of a running program rendering it unnecessary to realize NaN
in the machine. However, we can do that with NaT. The programmer
may have to deal with NaT on the meta-level, but the
meta-resolved program *must* be free of it, otherwise it's an
error. (In all the suggestions, having a bottom type meant that
declaring a variable of it is equivalent to assert(0);. This is a
huge difference. The bottom type is realized and this is part of
its semantics.)
More information about the Digitalmars-d
mailing list