November 30, 2012
On Thursday, 29 November 2012 at 23:02:17 UTC, Walter Bright wrote:
> On 11/30/2012 9:43 AM, Walter Bright wrote:
>> It is possible for each static constructor to specify independently of
>> the other static constructors which imports must be constructed first.
>> But do we really want to go that far?
>
> One way to do that might be to borrow syntax from classes:
>
>    static this() : std.stdio, a, c
>    {
>        ...
>    }
>
> and the  this static constructor only requires that modules std.stdio, a, and c be constructed first.
>
>    static this() : void
>    {
>        ...
>    }
>
> means it has no dependencies on other imports.
>
>    static this()
>    {
>       ...
>    }
>
> has the current behavior (all imported modules must be constructed first).

Why not simplify?

static this()
{
import std.stdio, a, c; // existing syntax
   ...
}

static this()
{ // no imports -> no dependencies
   ...
}

The current behavior should just be dropped.
November 30, 2012
On 11/29/2012 02:50 PM, Andrei Alexandrescu wrote:
> On 11/28/12 11:26 PM, bearophile wrote:
>> There are few things left to implement for purity (they are listed in
>> Bugzilla), but what's left to do for const and immutable?
>
> Construction flow and copy conversion.

... meaning e.g. being able to effectively .dup or .idup any class, struct, etc.?
November 30, 2012
On Friday, 30 November 2012 at 14:09:48 UTC, foobar wrote:
> Why not simplify?
>
> static this()
> {
> import std.stdio, a, c; // existing syntax
>    ...
> }
>
> static this()
> { // no imports -> no dependencies
>    ...
> }
>
> The current behavior should just be dropped.

+2
Simple & Elegant.

November 30, 2012
On Fri, 30 Nov 2012 14:29:19 -0000, Tove <tove@fransson.se> wrote:

> On Friday, 30 November 2012 at 14:09:48 UTC, foobar wrote:
>> Why not simplify?
>>
>> static this()
>> {
>> import std.stdio, a, c; // existing syntax
>>    ...
>> }
>>
>> static this()
>> { // no imports -> no dependencies
>>    ...
>> }
>>
>> The current behavior should just be dropped.
>
> +2
> Simple & Elegant.

-2
Confusing.  What is the scope of the import?  How does it interact with imports above/below the static this?

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
November 30, 2012
On 11/30/12 9:09 AM, foobar wrote:
> On Thursday, 29 November 2012 at 23:02:17 UTC, Walter Bright wrote:
>> On 11/30/2012 9:43 AM, Walter Bright wrote:
>>> It is possible for each static constructor to specify independently of
>>> the other static constructors which imports must be constructed first.
>>> But do we really want to go that far?
>>
>> One way to do that might be to borrow syntax from classes:
>>
>> static this() : std.stdio, a, c
[snip]
> Why not simplify?
[snip]

Why not further simplify?

static this()
{
    // JUST AS BEFORE
    ...
}

There is no need to redundantly specify what modules are used because... well they are right there in the body of the static constructor.

* no extra syntax
* no change in the symbol visibility rules (why are symbols invisible by default in static cdtors?)
* no change to the manual
* no breakage of existing code (only code that was broken will be accepted)
* no acceptance of actual circular dependencies go through compilation

This would be purely an improvement to the implementation that would allow more correct programs to compile. It's a removal of limitation - the best kind of language change there ever is.

We should have a "bootcamp" area with small compiler and library projects (such as this after we reach consensus). People who are interested in helping D, whether or not they've done it before, could find this area things that are well defined and will definitely be accepted if properly executed.


Andrei
November 30, 2012
On Friday, November 30, 2012 10:27:31 Artur Skawina wrote:
> On 11/29/12 23:34, Jonathan M Davis wrote:
> > On Thursday, November 29, 2012 23:28:07 Timon Gehr wrote:
> >> On 11/29/2012 01:17 PM, Jonathan M Davis wrote:
> >>> In the past when I've brought up similar solutions, he's been completely opposed to them. ...
> >> 
> >> It is not a solution, it is a workaround.
> > 
> > What do you mean? The runtime sees circular dependencies between modules even when there's no actual circular dependency between static constructors. We need to fix that. One way is to just make the runtime not care, which wouldn't be particularly safe. Another is to explicitly tell it that there are no such dependencies. I don't see how that's not a solution. And unless someone can come up with a way for the runtime to somehow determine on its own that there's no actual, circular dependency, I don't see how anything better could be done.
> 
> It's relatively easy for the /compiler/ to figure it out; it's just that
> implementing a simple user-provided flag requires the least amount of work.
> What Walter suggested can be tweaked to be sane (per-ctor flag) and will
> still be useful if/when the compiler becomes smarter (think lazily initted
> module fields).
> For the compiler to check if the value of every imported symbol accessed
> inside a mod-ctor can be evaluated at compile-time (if you encounter a case
> where this is not true it means there (potentially) is a true dependency and
> the ctors should be ordered) would require more work.

It can't be evaluated at compile time because of .di files. The compiler
doesn't necessarily have all of the source to work with - including the static
constructors - and if it doesn't have that, it can't do it. If anything figures
this out automatically, it has to be the runtime. If we can do that, great,
but it means that it'll have actually have to look at individual symbols
rather than just at the module level like it's doing now, and right now, we
have nothing even close to that. Regardless, while the compiler may be able
to provide additional information to the runtime, it's still the runtime that
needs to figure this out and not the compiler.

- Jonathan M Davis
November 30, 2012
On Friday, 30 November 2012 at 20:40:23 UTC, Jonathan M Davis wrote:
> It can't be evaluated at compile time because of .di files. The compiler
> doesn't necessarily have all of the source to work with - including the static
> constructors - and if it doesn't have that, it can't do it. If anything figures
> this out automatically, it has to be the runtime. If we can do that, great,
> but it means that it'll have actually have to look at individual symbols
> rather than just at the module level like it's doing now, and right now, we
> have nothing even close to that. Regardless, while the compiler may be able
> to provide additional information to the runtime, it's still the runtime that
> needs to figure this out and not the compiler.
>

I'd bet you can solve most cases anyway.
December 01, 2012
On 11/30/12 21:40, Jonathan M Davis wrote:
> On Friday, November 30, 2012 10:27:31 Artur Skawina wrote:
>> On 11/29/12 23:34, Jonathan M Davis wrote:
>>> On Thursday, November 29, 2012 23:28:07 Timon Gehr wrote:
>>>> On 11/29/2012 01:17 PM, Jonathan M Davis wrote:
>>>>> In the past when I've brought up similar solutions, he's been completely opposed to them. ...
>>>>
>>>> It is not a solution, it is a workaround.
>>>
>>> What do you mean? The runtime sees circular dependencies between modules even when there's no actual circular dependency between static constructors. We need to fix that. One way is to just make the runtime not care, which wouldn't be particularly safe. Another is to explicitly tell it that there are no such dependencies. I don't see how that's not a solution. And unless someone can come up with a way for the runtime to somehow determine on its own that there's no actual, circular dependency, I don't see how anything better could be done.
>>
>> It's relatively easy for the /compiler/ to figure it out; it's just that
>> implementing a simple user-provided flag requires the least amount of work.
>> What Walter suggested can be tweaked to be sane (per-ctor flag) and will
>> still be useful if/when the compiler becomes smarter (think lazily initted
>> module fields).
>> For the compiler to check if the value of every imported symbol accessed
>> inside a mod-ctor can be evaluated at compile-time (if you encounter a case
>> where this is not true it means there (potentially) is a true dependency and
>> the ctors should be ordered) would require more work.
> 
> It can't be evaluated at compile time because of .di files. The compiler

It can. The case where all definitions aren't available is of course a potential source of cycles and means that the ctors have to be run in order. There's no way around that, and it's where the attribute (nee pragma) helps, because it can be attached to the declaration, when the programmer thinks he knows better.

Andrei's naive suggestion would only handle the trivial toy example case, but fail for much of real code, that needs to access statically known properties of other modules. D has enough features that work for five-liners, but are unusable for real work.

The important points are that:

1) a ctor that does not access any symbol from another module is not treated
   as dependent on that module.
2) accessing just /types/ defined in another module works. No RT dep here.
3) reading known initialized constant data works. That's const/immutable/enum -
   again, those can never become a RT dep.
4) calling side-effect free code that does not depend on non-local state works.
   This is why an is-it-ctfeable check works - it will catch even the indirect deps.
   Yeah, it's conservative, but is has to be. A kind of 'pure-but-w/o-external-refs"
   thing would help further, but that can be added incrementally and may not even
   be necessary.

> have nothing even close to that. Regardless, while the compiler may be able to provide additional information to the runtime, it's still the runtime that needs to figure this out and not the compiler.

No. Would, at least, require going from per-module to per-symbol which is a *much* larger change than was proposed here. I don't even want to think about the (runtime) cost.

artur
December 01, 2012
On Saturday, 1 December 2012 at 10:54:37 UTC, Artur Skawina wrote:
> 3) reading known initialized constant data works. That's const/immutable/enum -
>    again, those can never become a RT dep.

const or immutable can be instanciated by another static ctor.

> 4) calling side-effect free code that does not depend on non-local state works.
>    This is why an is-it-ctfeable check works - it will catch even the indirect deps.
>    Yeah, it's conservative, but is has to be. A kind of 'pure-but-w/o-external-refs"
>    thing would help further, but that can be added incrementally and may not even
>    be necessary.
>

pure is probably enough. CTFEable is more restrictive.

>> have nothing even close to that. Regardless, while the compiler may be able
>> to provide additional information to the runtime, it's still the runtime that
>> needs to figure this out and not the compiler.
>

That is an undemonstrated assertion (and I think it is false).

> No. Would, at least, require going from per-module to per-symbol which is a *much*
> larger change than was proposed here. I don't even want to think about the (runtime)
> cost.
>

This reasonning is based on the assertion above, so is meaningless until the assertion is proven to be true.
December 01, 2012
On 12/01/12 12:29, deadalnix wrote:
> On Saturday, 1 December 2012 at 10:54:37 UTC, Artur Skawina wrote:
>> 3) reading known initialized constant data works. That's const/immutable/enum -
>>    again, those can never become a RT dep.
> 
> const or immutable can be instanciated by another static ctor.

The key words are "known" and "initialized". IOW

   const int a = 42;

doesn't add a dep, but

  const int a;

does.

/Modifying/ initialized const data from a mod ctor is (and should be) illegal.


>> 4) calling side-effect free code that does not depend on non-local state works.
>>    This is why an is-it-ctfeable check works - it will catch even the indirect deps.
>>    Yeah, it's conservative, but is has to be. A kind of 'pure-but-w/o-external-refs"
>>    thing would help further, but that can be added incrementally and may not even
>>    be necessary.
>>
> 
> pure is probably enough. CTFEable is more restrictive.

D's pure isn't enough, because it will allow accesses to external immutable
data - which can be modified by a mod ctor. But like i said - this might not be
a problem in practice, as it's just about the cross-module non-ctfeable, but
truly pure function calls inside mod ctors - is this really something that occurs
often enough?

>>> have nothing even close to that. Regardless, while the compiler may be able to provide additional information to the runtime, it's still the runtime that needs to figure this out and not the compiler.
>>
> 
> That is an undemonstrated assertion (and I think it is false).
> 
>> No. Would, at least, require going from per-module to per-symbol which is a *much* larger change than was proposed here. I don't even want to think about the (runtime) cost.
>>
> 
> This reasonning is based on the assertion above, so is meaningless until the assertion is proven to be true.

I'm not sure what assertion you think is false, but theoretically it /is/ possible
to figure out the deps at runtime, even w/o any hints. Think valgrind. But it's
a very bad idea, with a significant runtime cost (not as bad as valgrind since you
can figure out some things statically, but determining the order alone would already
be too slow for larger projects with many symbols and deps.)

artur