Re: general questions about static this() at module level

2016-10-31 Thread WhatMeWorry via Digitalmars-d-learn
On Monday, 31 October 2016 at 18:46:31 UTC, Jonathan M Davis 
wrote:
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).


Thanks! This is probably why I was not able to find a good code 
example in github. Not that I tried very hard when search 
returned over 10K occurrences of "static this". Seems this kind 
of higher level reasoning is missing from the books and 
documentation that I've read. Hope this kind of knowledge gets 
recorded somewhere.


Re: general questions about static this() at module level

2016-10-31 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: general questions about static this() at module level

2016-10-31 Thread Ali Çehreli via Digitalmars-d-learn

On 10/31/2016 09:02 AM, WhatMeWorry wrote:

> 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 usual, yes and no. :)

The former is initialized at compile-time, meaning that it's burned into 
the binary program to be placed on a page for such immutable values.


The latter is initialized at run-time, meaning that its location in 
memory will be filled with the run-time computed value of the expression.


As long as we treat immutable as immutable, from the point of view of 
the program the two behave the same. If we attempt to mutate immutable 
data, the outcome is undefined. The following program demonstrates that


1) The two kinds of immutables are placed in different places in memory 
('a' is nearby 'a0' but 'b' is elsewhere)


2) Although both 'a' and 'b' are mutated, the last assert fails 
presumably because the compiler happens to treat 'a' differently from 
'b' by using its compile-time value like an enum. In other words, 
although 'a' has a place in memory and we manage to change it,


assert(a == 43)

is compiled as

assert(42 == 43)

and fails. That's not the same with b. Again, none of this is defined 
anywhere in the language spec. If we mutate const or immutable data, the 
behavior is undefined.


import std.stdio;

immutable uint a0 = 10;
immutable uint a = 42;
immutable uint b;

static this() {
b = 42;
}

void info(T)(string tag, ref T t) {
writefln("%20s: %s %s @ %s", tag, T.stringof, t, );
}

void mutate(alias t)() {
info(t.stringof ~ " before", t);

import std.traits : Unqual;
auto p = cast(Unqual!(typeof(t))*)
*p = *p + 1;
info(t.stringof ~ " after ", t);
}

void main() {
info("a0 for reference", a0);
mutate!a;
mutate!b;

assert(b == 43);
assert(a == 43);  // <-- FAILS
}

May print

a0 for reference: immutable(uint) 10 @ 69D390
a before: immutable(uint) 42 @ 69D394
a after : immutable(uint) 43 @ 69D394
b before: immutable(uint) 42 @ 6A9F70
b after : immutable(uint) 43 @ 6A9F70
core.exception.AssertError@deneme.d(851): Assertion failure

Ali



Re: general questions about static this() at module level

2016-10-31 Thread WhatMeWorry via Digitalmars-d-learn

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;

}


Re: general questions about static this() at module level

2016-10-31 Thread ggdc via Digitalmars-d-learn

On Monday, 31 October 2016 at 04:35:35 UTC, WhatMeWorry wrote:

I am fascinated with D's module static this.

I have shamelessly stolen Ali's code directly from his book.

module cat;

static this() {
// ... the initial operations of the module ...
}
static ~this() {
// ... the final operations of the module ...
}


First, are there any other languages that has this feature?  
The few I know, certainly don't.




Object Pascal has them:


unit foo; // like a D module.

interface

// declarations...,
// like the content of a C/C++ *.h/*.hpp

implementation

// implementation like the content of a C/C++ *.c/*.cpp

initialization
// statements...
// like in a D static this(){}

finalization
// statements...
// like in a D static ~this(){}
end.


Actually without them a lot of stuffs wouldn't work properly.
They are more used than their D equivalent, particularly to
register classes for the object streaming system but not only.


Re: general questions about static this() at module level

2016-10-30 Thread sarn via Digitalmars-d-learn

On Monday, 31 October 2016 at 04:35:35 UTC, WhatMeWorry wrote:
First, are there any other languages that has this feature?  
The few I know, certainly don't.


I've seen hacks to do the same thing in C++.  They're not pretty, 
though.


And how would you compare and contrast these this(s) with those 
of structs and classes?
Like, are they especially good for certain D idioms, particular 
cases, or are they good in general?


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.


general questions about static this() at module level

2016-10-30 Thread WhatMeWorry via Digitalmars-d-learn

I am fascinated with D's module static this.

I have shamelessly stolen Ali's code directly from his book.

module cat;

static this() {
// ... the initial operations of the module ...
}
static ~this() {
// ... the final operations of the module ...
}


First, are there any other languages that has this feature?  The 
few I know, certainly don't.


And how would you compare and contrast these this(s) with those 
of structs and classes?
Like, are they especially good for certain D idioms, particular 
cases, or are they good in general?


Thirdly, can anyone point to existing code for good examples.

I searched on github for "static this" and 10,499 results were 
returned :)