Confusion/trying to understand CTFE keywords

Jonathan M Davis newsgroup.d at jmdavisprog.com
Fri Jun 8 18:45:01 UTC 2018


On Friday, June 08, 2018 03:51:11 David Bennett via Digitalmars-d-learn 
wrote:
> On Thursday, 7 June 2018 at 04:58:40 UTC, Jonathan M Davis wrote:
> > It would be trivial enough to create a wrapper template so that
> > you can do something like
> >
> > immutable n = ctfe!(foo());
> >
> > e.g.
> >
> > template ctfe(alias value)
> > {
> >
> >     enum ctfe = value;
> >
> > }
>
> Would this be equivalent to using static immutable?
>
> static immutable n = foo();
>
> In this case both the compiletime and runtime values were
> calculated using cfte.

No, they're not equivalent. That template definition just forces the value
to be calculated at compile time. It doesn't change anything about the
variable itself. Making the variable static means that there is only one
instance of the variable across all calls to the function. So, its address
is not within the stack of the function. Given that the variable is
immutable and thus cannot be changed means that that distinction doesn't
matter a lot in this case, but there's still a difference. And if you make
the variables mutable, it makes a huge difference. e.g

auto n = ctfe!(foo());

vs

static n = foo();

In both cases, the value is calculated at compile time, but in the first
case, you get a unique copy for each function call that does not exist
beyond that function call, whereas in the second case, it's reused for each
function call, so if you mutate it, subsequent calls will see the mutated
value (which would not be true if the variable weren't static).

> Also back to the OP the way I think of enum, static types is like
> this:
>
> alias and enum create compiletime stuff from compiletime stuff.
> static creates runtime stuff from compiletime stuff.
>
> Is that view valid in most cases?

Sort of but not really. enums are just names for compile-time values. As
such, they have to be calculated at compile time. static variables on the
other hand really have nothing to do with compile time per se. It's just
that they have a single location in memory for the entire thread of the
program. So, they get initialized when the thread is created and not when
the function is called and as such have to have their initial value known at
compile time unless a static constructor is used to initialize them. They're
either intialized with the init value for their type or the value that
they're given when declared. The exact same thing happens with member
variables. e.g.

struct S
{
    int i = foo();
}

makes it so that S.init.i is whatever value was the result of foo. If the
struct has a constructor, then that's the value of i before the constructor
is called. The init value for the struct must be known at compile time, so
any direct initialization is done at compile time (whereas if none is done,
then the init value for the type of the member variable is used). If the
member variable is const or immutable, then if it's directly initialized,
then it can't be assigned in the constructor, and if it's not directly
initialized, its init value is overwritten by the constructor and isn't
really used. But regardless, the init value must be known at compile time,
which means that any direct initialization must be calculated at compile
time.

So, the fact that static variables get their intial values at compile time
is just because of how they're intialized, not because of static
specifically being designed with compile-time anything in mind. The result
is that you then have a variable whose initial value was determined at
compile time and then can be manipulated at runtime (assuming that it's
mutable), but the key thing about static variables is their lifetime, not
that they're initialized at compile time.

If what you're really looking for is to calculate the value of a local
variable at compile-time, you're better off using an enum and then
initializing the local variable with the enum than using a static variable.
The only reason to use a static variable is if you specifically want a
variable whose lifetime is for the duration of the thread rather than the
duration of the function call. If you're using static just to get the value
calculated at compile time, you're increasing how much memory your thread
takes up when there really isn't a good reason to do so.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list