On Monday, October 31, 2016 16:02:13 WhatMeWorry via Digitalmars-d-learn 
wrote:
> On Monday, 31 October 2016 at 05:42:16 UTC, sarn wrote:
> > On Monday, 31 October 2016 at 04:35:35 UTC, WhatMeWorry wrote:
> >> [...]
> >
> > I've seen hacks to do the same thing in C++.  They're not
> > pretty, though.
> >
> >> [...]
> >
> > Class/struct static constructors are good for initialising
> > class/struct static data.  Module static constructors are good
> > for initialising module "static data" (i.e., globals).  They're
> > especially handy for initialising immutable global data (which
> > is the kind of global data D encourages).
> >
> > BTW, immutable data is shared between threads, so you should
> > use "shared static this" to initialise it.  Regular static
> > constructors are executed per thread.
>
> Thanks! If you don't mind a follow up question, is this:
>
> immutable uint maxSize = 128;
>
> identical to this:
>
> immutable uint maxSize;
>
> static this()
> {
>      maxSize = 128;
>
> }

As Ali points out, the first one is initialized at compile time and usable
at compile time, whereas the second is initialized at runtime and thus is
not usable at compile time.

It should be pointed out however, that it's an outstanding bug that
initializing an immutable variable with a non-shared static this is allowed.
As it stands, with the second example, maxSize would actually be initialized
once per thread, which is a problem, because immutable is implicitly shared.
It wouldn't really matter in this case, because it's a value type, and it's
always given the same value, but it's still not something that should be
allowed. Rather, it should be

shared static this()
{
    maxSize = 128;
}

though there's no reason to ever use a static constructor (shared or
otherwise) when you can directly initialize the variable. It's really meant
for more complicated initialization that can't be done directly.

Also, I would point out that in general, you'll be better off if you avoid
static constructors and destructors. They can be extremely useful, but if
multiple modules use them, and one imports the other (even indirectly), and
the runtime thinks that that dependency is circular, then it'll throw an
Error when you start your program (this comes from the fact that the runtime
has to determine the order to run the static constructors so that everything
is initialized before it's used, but it's not very smart about it, since it
bases what it does solely on the presense of static constructors in a module
and not what they actually do). So, if you ever end up with any kind of
circular imports (even indirectly), you can run into problems. Because of
issues related to that, static constructors border on being banned in Phobos
(they're still used in rare cases, but they're avoided if they're not truly
needed, and we try not to need them).

So, while static constructors are a great feature, they can cause problems
if use them heavily.

As to your original question about other languages that have them, IIRC,
Java has static constructors (but I don't think that it has static
destructors), if Java has it, C# almost certainly does as well. C++ does not
though, which can be really annoying. It can be faked via RAII and static
variables, but in general, using static variables in C++ is pretty iffy,
because the order of intializaton is undefined (which shows that the
annoyances with druntime detecting circular imports with static constructors
and complaining about them are well worth the pain, though it would be nice
if druntime were able to be smarter about it). So, D's static constructors
and destructors are a huge improvement over what C++ has.

- Jonathan M Davis

Reply via email to