Thread overview
Re: namespace (for export)
Nov 25, 2010
Jonathan M Davis
Nov 25, 2010
spir
Nov 25, 2010
Simen kjaeraas
Nov 25, 2010
spir
Nov 25, 2010
Jonathan M Davis
November 25, 2010
On Thursday 25 November 2010 02:09:27 spir wrote:
> Hello,
> 
> 
> In a previous post, I asked how to define, in a module, a set of symbols for export.
> 
> I was blocked then mainly because the compiler did not let me freely define what I wanted to define, at the module's toplevel. Especially, it does not allow accessing (public) fields or methods of defined elements. A first question is why, because for me a field is just a special var, and a method just a special func. The language seems to let call any other kind of func, or access any other kind of var (I have not stepped on other limitations).
> 
> All those blockages magically disappear when put inside a 'static this () {} block'. This firstly shows that the language is fully capable of coping with "free" definitions; and to make them available for export. So, why not allow them at the module's toplevel? I cannot see any difference from the language's point of view.
> 
> An annoying consequence is that what's defined inside 'static this' is not available in the module itself (EDIT: they seem not to be available for export, neither). I cannot test them, for instance. They must be globally declared, forcing to repete ids in 2 separate locations in code, leading to bugs after any edit (frustrating ones, like in those languages where interface must repeat implementation).
> 
> Finally, I guess from "static" in "static this" that the issue's key point has something to do with evaluation at compile-time. Maybe I'm completely stupid in thinking this, but why should the compiler be able to evaluate a module's top-level symbols at compile-time? What we want is them to be available at _import_ time. In my view, the compiler's task here to build a representation of the code (ie to compile, not to evaluate), e basta. Like a func def, which will is run when called only. For a module's toplevel, call-time is import-time. (For an app's single or main module, call-time is just run.)
> 
> These reflexions probably show you how I'm missing some fondamental point here -- about staticity, certainly. Please help me understand ;-), if it is the case.

All variables must either be within the global scope, a class, a struct, or a function (including unittest blocks and static constructors which are actually functions, albeit special ones).

All statements must be within a function.

I really don't get what you're trying to do, since previous posts on this topic that you've made indicate that you're trying to put statements at the module level, which makes no sense at all. All statements must be in a function and thus have an execution path. The module itself is for declarations only. It has no execution path, so it never run statements, and so it makes no sense to put them there. All a module constructor is for is initializing global variables at runtime. It's completely different from trying to put statements directly in the module.

If you want to take code in one module and paste it into another, you probably either want string mixins or template mixins: http://www.digitalmars.com/d/2.0/template-mixin.html

Hopefully that's of some help. But you seem to be trying to do something so alien that I'm really having trouble understanding it is that you're trying to do.

- Jonathan M Davis
November 25, 2010
On Thu, 25 Nov 2010 03:03:24 -0800
Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> I really don't get what you're trying to do, since previous posts on this topic
that you've made indicate that you're trying to put statements at the module level, which makes no sense at all. All statements must be in a function and thus have an execution path.

In the general case, defining symbols requires kinds of statement (but I don't see what you mean by "statement" as for me an assignemnt is the archetype of a statement, so how can you define anything?). Anyway, if I put definitions in a func, as you propose, then how can I have the symbols available for export? The answer seems to be: declare them first as globals. Right, but then we get this double definition issue (not that serious, just annoying); it's just a useless hack.
What I don't understand is why the language refuses the same exact definition at the toplevel that it accepts in a func.
You seems to take it for granted that I cannot write:
	auto myExportedSymbol = new T();
	...
	myExportedSymbol.i = 1;
but for me there is no obvious reason why D refuses that, and accepts
	T myExportedSymbol;
	static this () {
	   auto myExportedSymbol = new T();
	   ...
	   myExportedSymbol.i = 1;
	}
It's the same thing, from my point of view: when I import the module, I get the symbol correctly defined. I don't get why a module needs a constructor: why else has it a top-level?

> All a module constructor is for is initializing global variables at runtime.

Precising runtime to import time, that's exactly what I'm looking for. How can one do it without static this?

Denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com

November 25, 2010
spir <denis.spir@gmail.com> wrote:

> In the general case, defining symbols requires kinds of statement (but I don't see what you mean by "statement" as for me an assignemnt is the archetype of a statement, so how can you define anything?).

http://digitalmars.com/d/2.0/declaration.html

A variable declaration is a declaration, not a statement. Note also that
initialization is included, so int i = 4; works.


> Anyway, if I put definitions in a func, as you propose, then how can I have the symbols available for export? The answer seems to be: declare them first as globals. Right, but then we get this double definition issue (not that serious, just annoying); it's just a useless hack.
> What I don't understand is why the language refuses the same exact definition at the toplevel that it accepts in a func.

Because run time code can not be run at arbitrary points in a D program
like you'd expect from a more dynamic language like python.

Note however, that some code may be evaluated at compile time:
http://www.digitalmars.com/d/2.0/function.html#interpretation


> You seems to take it for granted that I cannot write:
> 	auto myExportedSymbol = new T();
> 	...
> 	myExportedSymbol.i = 1;
> but for me there is no obvious reason why D refuses that, and accepts
> 	T myExportedSymbol;
> 	static this () {
> 	   auto myExportedSymbol = new T();
> 	   ...
> 	   myExportedSymbol.i = 1;
> 	}
> It's the same thing, from my point of view: when I import the module, I get the symbol correctly defined. I don't get why a module needs a constructor: why else has it a top-level?

The reason for this is partly historical (C does it this way), but more
importantly, practical. This way it is obvious what code will be executed
at which time, and code is not as easily 'hidden' between type and
variable declarations.


>> All a module constructor is for is initializing global variables at
>> runtime.
>
> Precising runtime to import time, that's exactly what I'm looking for. How can one do it without static this?

You can't.


-- 
Simen
November 25, 2010
On Thu, 25 Nov 2010 19:28:13 +0100
"Simen kjaeraas" <simen.kjaras@gmail.com> wrote:

> > You seems to take it for granted that I cannot write:
> > 	auto myExportedSymbol = new T();
> > 	...
> > 	myExportedSymbol.i = 1;
> > but for me there is no obvious reason why D refuses that, and accepts
> > 	T myExportedSymbol;
> > 	static this () {
> > 	   auto myExportedSymbol = new T();
> > 	   ...
> > 	   myExportedSymbol.i = 1;
> > 	}
> > It's the same thing, from my point of view: when I import the module, I
> > get the symbol correctly defined. I don't get why a module needs a
> > constructor: why else has it a top-level?
> 
> The reason for this is partly historical (C does it this way), but more importantly, practical. This way it is obvious what code will be executed at which time, and code is not as easily 'hidden' between type and variable declarations.

Thank you, Simen, I get it better. I have a solution with static this anyway, even if not completely satisfying. Simply tried  to understand better the whys and hows.
(And sorry all for the somewhat frustrated tone of a few posts by me.)


Denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com

November 25, 2010
On Thursday 25 November 2010 09:55:44 spir wrote:
> On Thu, 25 Nov 2010 03:03:24 -0800
> 
> Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> > I really don't get what you're trying to do, since previous posts on this topic
> 
> that you've made indicate that you're trying to put statements at the module level, which makes no sense at all. All statements must be in a function and thus have an execution path.
> 
> In the general case, defining symbols requires kinds of statement (but I
> don't see what you mean by "statement" as for me an assignemnt is the
> archetype of a statement, so how can you define anything?). Anyway, if I
> put definitions in a func, as you propose, then how can I have the symbols
> available for export? The answer seems to be: declare them first as
> globals. Right, but then we get this double definition issue (not that
> serious, just annoying); it's just a useless hack. What I don't understand
> is why the language refuses the same exact definition at the toplevel that
> it accepts in a func. You seems to take it for granted that I cannot
> write:
> 	auto myExportedSymbol = new T();
> 	...
> 	myExportedSymbol.i = 1;
> but for me there is no obvious reason why D refuses that, and accepts
> 	T myExportedSymbol;
> 	static this () {
> 	   auto myExportedSymbol = new T();
> 	   ...
> 	   myExportedSymbol.i = 1;
> 	}
> It's the same thing, from my point of view: when I import the module, I get
> the symbol correctly defined. I don't get why a module needs a
> constructor: why else has it a top-level?
> 
> > All a module constructor is for is initializing global variables at runtime.
> 
> Precising runtime to import time, that's exactly what I'm looking for. How can one do it without static this?

1. All declarations other than non-static locals are done at compile time. Conceptually, they can run in any order. Unlike in a function, there is no execution path for them to be run on. So, if you have

int i = 7;
float g = 2.1;

there's nothing that says that i must be initialized before g. Such declarations are purely declarative in nature such as you'd expect from declarative programming.

2. static this blocks - be they module constructors or static class or static struct constructors - are essentially special functions which are run in lexical order in each module prior to main (and prior to the unittest blocks if - unittest is used). They're completely at runtime and provide an execution path statements so that you can initialize globals and static class/struct variables with stuff that can only be done at runtime or uses other globals or statics as part of the initialization. Modules which circularly import each other cannot have module constructors precisely because that creates problems with knowing the proper order to run the module constructors to avoid interdependencies and thus avoid trying to use a variable before it has actually been initialized.

3. imports import the symbols table. The code may or may not have been fully compiled before an import is processed. If modules are interdependent, then it can't have been. importing a module also cannot affect the module being imported, or the order of imports and the order of the compilation of modules matters, and whether you import a particular module could affect other modules. Modules are independent, can be compiled in any order - barring interdependencies - and are only compiled once. So, having a module affected by a module importing it does not work at all. And because symbols can at least be partially - if not fully - compiled independently, having a global variable affected by whether it was imported or not doesn't work at all - especially when it could be a third party which imports it. If your module were in a compiled library (be it shared or static), and someone using that library imports it, your code has already been compiled and all compile-time initialization done, so it there's no way that you could have modules be affected by who imports them or even know whether any modules actually do import them.

It is true that some languages do not make symbols as independent of each other as D does - C and C++ are particularly bad with how #include works - and for a number of languages, global variables are initialized at runtime in lexigraphical order (C++ and Java both do that), but that creates interdependencies and bugs which only pop up at runtime when variables were declared in a particular order. It's very messy, although if you're careful or don't do much with globals or static variables, it's not generally a problem. D doesn't do things that way. It made it so that all global and static variables must be initialized at compile-time (avoiding all of the ordering and interdependcy problems except for those posed by module constructors). This not only avoids bugs, but it makes it possible for the compiler to parallelize their compilation on a _much_ greater level than would be possible in a language like C++ or Java. And while, languages like C++ and Java do do global initializations at runtime and in do it lexographical order, they're still conceptually doing declarative programming, so it really doesn't make sense for them to put statements directly in the module either (though in their case, the implementation doesn't quite match the concept). Java added static constructors to help fix the problem, and D took it a step further by making global initializations have to be done at compile time or in a static constructor.

So, what you're trying to do just doesn't work with D's compilation model, or really the compilation model of any C-based language, I don't believe. In D, modules are essentially independent, and all compilation is made as independent as possible. Obviously, there is a dependence on order in functions (be they static constructors or normal functions), but that's pretty much the only place that order matters. So, I really don't think that you're going to be able to do what you're trying to do like you've been trying to do it.

- Jonathan M Davis