Jump to page: 1 212  
Page
Thread overview
Program size, linking matter, and static this()
Dec 16, 2011
Nick Sabalausky
Dec 16, 2011
Jacob Carlborg
Dec 16, 2011
Jacob Carlborg
Dec 16, 2011
Adam D. Ruppe
Dec 18, 2011
Marco Leise
Dec 16, 2011
Sean Kelly
Jan 18, 2012
Martin Nowak
Dec 16, 2011
torhu
Dec 16, 2011
Jonathan M Davis
Dec 19, 2011
torhu
Dec 19, 2011
Jacob Carlborg
Dec 20, 2011
Marco Leise
Dec 20, 2011
dsimcha
Dec 16, 2011
Jacob Carlborg
Dec 16, 2011
Jonathan M Davis
Dec 16, 2011
Timon Gehr
Dec 16, 2011
Jonathan M Davis
Dec 16, 2011
Timon Gehr
Dec 16, 2011
Jonathan M Davis
Dec 16, 2011
Timon Gehr
Dec 16, 2011
maarten van damme
Dec 16, 2011
Walter Bright
Dec 16, 2011
Sean Kelly
Dec 16, 2011
Timon Gehr
Dec 17, 2011
Somedude
Dec 16, 2011
Jonathan M Davis
Dec 17, 2011
Jonathan M Davis
Dec 17, 2011
deadalnix
Dec 18, 2011
Jonathan M Davis
Dec 18, 2011
Somedude
Dec 17, 2011
so
Dec 17, 2011
so
Dec 17, 2011
Jakob Ovrum
Dec 18, 2011
so
Dec 18, 2011
Jakob Ovrum
Dec 18, 2011
Jakob Ovrum
Dec 18, 2011
Jonathan M Davis
Dec 16, 2011
Walter Bright
Jan 18, 2012
Martin Nowak
Jan 18, 2012
Martin Nowak
Dec 16, 2011
Jonathan M Davis
Dec 16, 2011
Sean Kelly
Dec 16, 2011
Timon Gehr
Dec 17, 2011
bearophile
Dec 16, 2011
Jonathan M Davis
Dec 17, 2011
Walter Bright
Dec 17, 2011
Jonathan M Davis
Dec 16, 2011
Sean Kelly
Dec 16, 2011
Trass3r
Dec 16, 2011
Trass3r
Dec 16, 2011
Timon Gehr
Dec 16, 2011
Bane
Dec 16, 2011
Adam D. Ruppe
Dec 16, 2011
Walter Bright
Dec 19, 2011
Walter Bright
Dec 19, 2011
Walter Bright
Dec 20, 2011
Marco Leise
Dec 21, 2011
Jonathan M Davis
Dec 21, 2011
Jakob Ovrum
Dec 21, 2011
Jonathan M Davis
Dec 21, 2011
so
Dec 21, 2011
Michal Minich
Dec 21, 2011
Jonathan M Davis
Dec 16, 2011
Sean Kelly
Dec 17, 2011
Somedude
Dec 16, 2011
Sean Kelly
Dec 16, 2011
Sean Kelly
Dec 16, 2011
torhu
Dec 16, 2011
Richard Webb
Dec 16, 2011
Sean Kelly
Dec 17, 2011
Martin Nowak
Dec 17, 2011
Martin Nowak
Dec 20, 2011
Denis Shelomovskij
Dec 20, 2011
Walter Bright
Dec 21, 2011
Denis Shelomovskij
Dec 20, 2011
Marco Leise
Dec 20, 2011
Walter Bright
Dec 21, 2011
Marco Leise
Dec 21, 2011
Walter Bright
Dec 27, 2011
Marco Leise
Jan 18, 2012
Marco Leise
Jan 18, 2012
Walter Bright
Jan 18, 2012
Marco Leise
Jan 19, 2012
Marco Leise
Jan 19, 2012
Marco Leise
Dec 20, 2011
Vladimir Panteleev
December 16, 2011
Hello,


Late last night Walter and I figured a few interesting tidbits of information. Allow me to give some context, discuss them, and sketch a few approaches for improving things.

A while ago Walter wanted to enable function-level linking, i.e. only get the needed functions from a given (and presumably large) module. So he arranged things that a library contains many small object "files" (that actually are generated from a single .d file and never exist on disk, only inside the library file, which can be considered an archive like tar). Then the linker would only pick the used object "files" from the library and link those in. Unfortunately that didn't have nearly the expected impact - essentially the size of most binaries stayed the same. The mystery was unsolved, and Walter needed to move on to other things.

One particularly annoying issue is that even programs that don't ostensibly use anything from an imported module may balloon inexplicably in size. Consider:

import std.path;
void main(){}

This program, after stripping and all, has some 750KB in size. Removing the import line reduces the size to 218KB. That includes the runtime support, garbage collector, and such, and I'll consider it a baseline. (A similar but separate discussion could be focused on reducing the baseline size, but herein I'll consider it constant.)

What we'd simply want is to be able to import stuff without blatantly paying for what we don't use. If a program imports std.path and uses no function from it, it should be as large as a program without the import. Furthermore, the increase should be incremental - using 2-3 functions from std.path should only increase the executable size by a little, not suddenly link in all code in that module.

But in experiments it seemed like program size would increase in sudden amounts when certain modules were included. After much investigation we figured that the following fateful causal sequence happened:

1. Some modules define static constructors with "static this()" or "static shared this()", and/or static destructors.

2. These constructors/destructors are linked in automatically whenever a module is included.

3. Importing a module with a static constructor (or destructor) will generate its ModuleInfo structure, which contains static information about all module members. In particular, it keeps virtual table pointers for all classes defined inside the module.

4. That means generating ModuleInfo refers all virtual functions defined in that module, whether they're used or not.

5. The phenomenon is transitive, e.g. even if std.path has no static constructors but imports std.datetime which does, a ModuleInfo is generated for std.path too, in addition to the one for std.datetime. So now classes inside std.path (if any) will be all linked in.

6. It follows that a module that defines classes which in turn use other functions in other modules, and has static constructors (or includes other modules that do) will baloon the size of the executable suddenly.

There are a few approaches that we can use to improve the state of affairs.

A. On the library side, use static constructors and destructors sparingly inside druntime and std. We can use lazy initialization instead of compulsively initializing library internals. I think this is often a worthy thing to do in any case (dynamic libraries etc) because it only does work if and when work needs to be done at the small cost of a check upon each use.

B. On the compiler side, we could use a similar lazy initialization trick to only refer class methods in the module if they're actually needed. I'm being vague here because I'm not sure what and how that can be done.

Here's a list of all files in std using static cdtors:

std/__fileinit.d
std/concurrency.d
std/cpuid.d
std/cstream.d
std/datebase.d
std/datetime.d
std/encoding.d
std/internal/math/biguintcore.d
std/internal/math/biguintx86.d
std/internal/processinit.d
std/internal/windows/advapi32.d
std/mmfile.d
std/parallelism.d
std/perf.d
std/socket.d
std/stdiobase.d
std/uri.d

The majority of them don't do a lot of work and are not much used inside phobos, so they don't blow up the executable. The main one that could receive some attention is std.datetime. It has a few static ctors and a lot of classes. Essentially just importing std.datetime or any std module that transitively imports std.datetime (and there are many of them) ends up linking in most of Phobos and blows the size up from the 218KB baseline to 700KB.

Jonathan, could I impose on you to replace all static cdtors in std.datetime with lazy initialization? I looked through it and it strikes me as a reasonably simple job, but I think you'd know better what to do than me.

A similar effort could be conducted to reduce or eliminate static cdtors from druntime. I made the experiment of commenting them all, and that reduced the size of the baseline from 218KB to 200KB. This is a good amount, but not as dramatic as what we can get by working on std.datetime.


Thanks,

Andrei
December 16, 2011
Interesting stuff.

"Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:jcg2lu$17p2$1@digitalmars.com...
>
> We can use lazy initialization instead of compulsively initializing library internals. I think this is often a worthy thing to do in any case (dynamic libraries etc) because it only does work if and when work needs to be done at the small cost of a check upon each use.
>

That also has the benefit of reducing the risk of dreaded circular ctor dependency problems.


December 16, 2011
On Fri, 16 Dec 2011 13:29:18 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> Hello,
>
>
> Late last night Walter and I figured a few interesting tidbits of information. Allow me to give some context, discuss them, and sketch a few approaches for improving things.
>
> A while ago Walter wanted to enable function-level linking, i.e. only get the needed functions from a given (and presumably large) module. So he arranged things that a library contains many small object "files" (that actually are generated from a single .d file and never exist on disk, only inside the library file, which can be considered an archive like tar). Then the linker would only pick the used object "files" from the library and link those in. Unfortunately that didn't have nearly the expected impact - essentially the size of most binaries stayed the same. The mystery was unsolved, and Walter needed to move on to other things.
>
> One particularly annoying issue is that even programs that don't ostensibly use anything from an imported module may balloon inexplicably in size. Consider:
>
> import std.path;
> void main(){}
>
> This program, after stripping and all, has some 750KB in size. Removing the import line reduces the size to 218KB. That includes the runtime support, garbage collector, and such, and I'll consider it a baseline. (A similar but separate discussion could be focused on reducing the baseline size, but herein I'll consider it constant.)
>
> What we'd simply want is to be able to import stuff without blatantly paying for what we don't use. If a program imports std.path and uses no function from it, it should be as large as a program without the import. Furthermore, the increase should be incremental - using 2-3 functions from std.path should only increase the executable size by a little, not suddenly link in all code in that module.
>
> But in experiments it seemed like program size would increase in sudden amounts when certain modules were included. After much investigation we figured that the following fateful causal sequence happened:
>
> 1. Some modules define static constructors with "static this()" or "static shared this()", and/or static destructors.
>
> 2. These constructors/destructors are linked in automatically whenever a module is included.
>
> 3. Importing a module with a static constructor (or destructor) will generate its ModuleInfo structure, which contains static information about all module members. In particular, it keeps virtual table pointers for all classes defined inside the module.
>
> 4. That means generating ModuleInfo refers all virtual functions defined in that module, whether they're used or not.
>
> 5. The phenomenon is transitive, e.g. even if std.path has no static constructors but imports std.datetime which does, a ModuleInfo is generated for std.path too, in addition to the one for std.datetime. So now classes inside std.path (if any) will be all linked in.
>
> 6. It follows that a module that defines classes which in turn use other functions in other modules, and has static constructors (or includes other modules that do) will baloon the size of the executable suddenly.
>
> There are a few approaches that we can use to improve the state of affairs.
>
> A. On the library side, use static constructors and destructors sparingly inside druntime and std. We can use lazy initialization instead of compulsively initializing library internals. I think this is often a worthy thing to do in any case (dynamic libraries etc) because it only does work if and when work needs to be done at the small cost of a check upon each use.
>
> B. On the compiler side, we could use a similar lazy initialization trick to only refer class methods in the module if they're actually needed. I'm being vague here because I'm not sure what and how that can be done.
>

I disagree with this assessment.  It's good to know the cause of the problem, but let's look at the root issue -- reflection.  The only reason to include class information for classes not being referenced is to be able to construct/use classes at runtime instead of at compile time.  But if you look at D's runtime reflection capabilities, they are quite poor.  You can only construct a class at runtime if it has a zero-arg constructor.

So essentially, we are paying the penalty of having runtime reflection in terms of bloat, but get very very little benefit.

I think there are two things that need to be considered:

1. We eventually should have some reasonably complete runtime reflection capability
2. Runtime reflection and shared libraries go hand-in-hand.  With shared library support, the bloat penalty isn't nearly as significant.

I don't think the right answer is to avoid using features of the language because the compiler/runtime has some design deficiencies.  At some point these deficiencies will be fixed, and then we are left with a library that has seemingly odd design choices that we can't change.

-Steve
December 16, 2011
On Friday, December 16, 2011 12:29:18 Andrei Alexandrescu wrote:
> Jonathan, could I impose on you to replace all static cdtors in std.datetime with lazy initialization? I looked through it and it strikes me as a reasonably simple job, but I think you'd know better what to do than me.
> 
> A similar effort could be conducted to reduce or eliminate static cdtors from druntime. I made the experiment of commenting them all, and that reduced the size of the baseline from 218KB to 200KB. This is a good amount, but not as dramatic as what we can get by working on std.datetime.

Hmm. I had reply for this already, but it seems to have disappeared, so I'll try again.

You could make core.time use property functions instead of the static immutable variables that it's using now for ticksPerSec and appOrigin, but in order to do that right would require introducing a mutex or synchronized block (which is really just a mutex under the hood anyway), and I'm loathe to do that in time-related code. ticksPerSec gets used all over the place in TickDuration, and that could have a negative impact on performance for something that needs to be really fast (since it's used in stuff like StopWatch and benchmarking). On top of that, in order to maintain the current semantics, the property functions would have to be pure, which they can't be without doing some nasty casting to convince the compiler that stuff which isn't pure is actually pure.

For std.datetime, the problem would be reduced if a class could be created in CTFE and still be around at runtime, but we can't do that yet, and it wouldn't completely solve the problem, since the shared static constructor related to LocalTime has to call tzset. So, some sort of runtime initialization must be done. And the instances for the singleton are not only immutable, but the functions for getting them are pure. So, once again, some nasty casting would be required to get it to work without breaking purity. And once again, we'd have introduce a mutex. And for both core.time and std.datetime we're talking about a mutex would be needed only briefly to ensure that we don't end up with two threads trying to initialize the variable at the same time. After that, it would just be impeding performance for no value. They're classic situations for static constructors - initializing static immutable variables - and really, they _should_ be using static constructors. If we have to get rid of them, it's to get around other problems in the language or compiler instead of fixing those problems. So, on some level, that seems like a failure on the part of the language and the compiler. If we _have_ to find a workaround, then we have to find a workaround, but I find the need to be distasteful to say the least. I previously tried to get rid of the static constructors in std.datetime and couldn't precisely because they're needed unless you play major casting games to get around immutable and pure.

If we play nice, it's impossible to get rid of the static constructors in std.datetime. It probably is possible if we do nasty casting, but (much as I hate to use the word) it seems like this is a hack to get around the fact that the compiler isn't dealing with static constructors as well as we'd like. I'd _really_ like to see this fixed at the compiler level.

And honestly, I think that a far worse problem with static constructors is circular dependencies. _That_ is something that needs to be addressed with regards to static constructors. In general at this point, it's looking like static constructors are turning out to be a bit of a failure on some level, given the issues that we're having because of them, and I think that we should fix the language and/or compiler so that they _aren't_ a failure.

- Jonathan M Davis
December 16, 2011
On 12/16/11 1:23 PM, Steven Schveighoffer wrote:
> I disagree with this assessment. It's good to know the cause of the
> problem, but let's look at the root issue -- reflection. The only reason
> to include class information for classes not being referenced is to be
> able to construct/use classes at runtime instead of at compile time. But
> if you look at D's runtime reflection capabilities, they are quite poor.
> You can only construct a class at runtime if it has a zero-arg constructor.
>
> So essentially, we are paying the penalty of having runtime reflection
> in terms of bloat, but get very very little benefit.

I'd almost agree, but the code showed doesn't use Object.factory(). So that shouldn't be linked in, and shouldn't pull vtables.

> I think there are two things that need to be considered:
>
> 1. We eventually should have some reasonably complete runtime reflection
> capability
> 2. Runtime reflection and shared libraries go hand-in-hand. With shared
> library support, the bloat penalty isn't nearly as significant.
>
> I don't think the right answer is to avoid using features of the
> language because the compiler/runtime has some design deficiencies. At
> some point these deficiencies will be fixed, and then we are left with a
> library that has seemingly odd design choices that we can't change.

Runtime reflection is great, but I think it's a separate issue from what's discussed here.


Andrei


December 16, 2011
On 12/16/2011 08:41 PM, Jonathan M Davis wrote:
> On Friday, December 16, 2011 12:29:18 Andrei Alexandrescu wrote:
>> Jonathan, could I impose on you to replace all static cdtors in
>> std.datetime with lazy initialization? I looked through it and it
>> strikes me as a reasonably simple job, but I think you'd know better
>> what to do than me.
>>
>> A similar effort could be conducted to reduce or eliminate static cdtors
>> from druntime. I made the experiment of commenting them all, and that
>> reduced the size of the baseline from 218KB to 200KB. This is a good
>> amount, but not as dramatic as what we can get by working on std.datetime.
>
> Hmm. I had reply for this already, but it seems to have disappeared, so I'll
> try again.
>
> You could make core.time use property functions instead of the static
> immutable variables that it's using now for ticksPerSec and appOrigin, but in
> order to do that right would require introducing a mutex or synchronized block
> (which is really just a mutex under the hood anyway), and I'm loathe to do
> that in time-related code. ticksPerSec gets used all over the place in
> TickDuration, and that could have a negative impact on performance for
> something that needs to be really fast (since it's used in stuff like StopWatch
> and benchmarking). On top of that, in order to maintain the current semantics,
> the property functions would have to be pure, which they can't be without
> doing some nasty casting to convince the compiler that stuff which isn't pure
> is actually pure.

lazy variables would resolve this.

>
> For std.datetime, the problem would be reduced if a class could be created in
> CTFE and still be around at runtime, but we can't do that yet, and it wouldn't
> completely solve the problem, since the shared static constructor related to
> LocalTime has to call tzset. So, some sort of runtime initialization must be
> done. And the instances for the singleton are not only immutable, but the
> functions for getting them are pure. So, once again, some nasty casting would
> be required to get it to work without breaking purity. And once again, we'd
> have introduce a mutex. And for both core.time and std.datetime we're talking
> about a mutex would be needed only briefly to ensure that we don't end up with
> two threads trying to initialize the variable at the same time. After that, it
> would just be impeding performance for no value. They're classic situations
> for static constructors - initializing static immutable variables - and
> really, they _should_ be using static constructors. If we have to get rid of
> them, it's to get around other problems in the language or compiler instead of
> fixing those problems. So, on some level, that seems like a failure on the part
> of the language

no.

> and the compiler.

yes. Although I am not severely affected by 500kb of bloat.

> If we _have_ to find a workaround, then we
> have to find a workaround, but I find the need to be distasteful to say the
> least. I previously tried to get rid of the static constructors in
> std.datetime and couldn't precisely because they're needed unless you play
> major casting games to get around immutable and pure.
>
> If we play nice, it's impossible to get rid of the static constructors in
> std.datetime. It probably is possible if we do nasty casting, but (much as I
> hate to use the word) it seems like this is a hack to get around the fact that
> the compiler isn't dealing with static constructors as well as we'd like. I'd
> _really_ like to see this fixed at the compiler level.
>
> And honestly, I think that a far worse problem with static constructors is
> circular dependencies. _That_ is something that needs to be addressed with
> regards to static constructors.

Circular dependencies are not to be blamed on the design of static constructors.

> In general at this point, it's looking like
> static constructors are turning out to be a bit of a failure on some level,
> given the issues that we're having because of them, and I think that we should
> fix the language and/or compiler so that they _aren't_ a failure.
>
> - Jonathan M Davis


We are having (minor!!) problems because the task of initializing global data in a modular way is inherently hard.

Just have a look how other languages handle initialization of global data and you'll notice that the D solution is actually very sensible.
December 16, 2011
On Friday, December 16, 2011 21:06:49 Timon Gehr wrote:
> On 12/16/2011 08:41 PM, Jonathan M Davis wrote:
> > On Friday, December 16, 2011 12:29:18 Andrei Alexandrescu wrote:
> >> Jonathan, could I impose on you to replace all static cdtors in std.datetime with lazy initialization? I looked through it and it strikes me as a reasonably simple job, but I think you'd know better what to do than me.
> >> 
> >> A similar effort could be conducted to reduce or eliminate static
> >> cdtors
> >> from druntime. I made the experiment of commenting them all, and that
> >> reduced the size of the baseline from 218KB to 200KB. This is a good
> >> amount, but not as dramatic as what we can get by working on
> >> std.datetime.>
> > Hmm. I had reply for this already, but it seems to have disappeared, so I'll try again.
> > 
> > You could make core.time use property functions instead of the static immutable variables that it's using now for ticksPerSec and appOrigin, but in order to do that right would require introducing a mutex or synchronized block (which is really just a mutex under the hood anyway), and I'm loathe to do that in time-related code. ticksPerSec gets used all over the place in TickDuration, and that could have a negative impact on performance for something that needs to be really fast (since it's used in stuff like StopWatch and benchmarking). On top of that, in order to maintain the current semantics, the property functions would have to be pure, which they can't be without doing some nasty casting to convince the compiler that stuff which isn't pure is actually pure.
> 
> lazy variables would resolve this.

True, but we don't have them.

> Circular dependencies are not to be blamed on the design of static constructors.

Yes they are. static constructors completely chicken out on them. Not only is there no real attempt to determine whether the static constructors are actually dependent (which granted, isn't an easy problem), but there is _zero_ support in the language for resolving such circular dependencies. There's no way to say that they _aren't_ dependent even if you can clearly see that they aren't. The solution used in Phobos (which won't work in std.datetime due to the use of immutable and pure) is to create a C module which has the code from the static constructor and then have a separate module which calls it in its static constructor. It works, but it's not pretty (and it doesn't always work - e.g. std.datetime), and it would be _far_ better if you could just mark a static constructor as not depending on anything or mark it as not depending on a specific module or something similar. And given how disgusting it generally is to even figure out what's causing a circular dependency when the runtime won't start your program because of it, I really think that this is a problem which should resolved. static constructors need to be improved.

> > In general at this point, it's looking like
> > static constructors are turning out to be a bit of a failure on some
> > level, given the issues that we're having because of them, and I think
> > that we should fix the language and/or compiler so that they _aren't_ a
> > failure.
> > 
> > - Jonathan M Davis
> 
> We are having (minor!!) problems because the task of initializing global data in a modular way is inherently hard.
> 
> Just have a look how other languages handle initialization of global data and you'll notice that the D solution is actually very sensible.

Yes. The situation with D is better than that of many other languages, but what prodblems we do have can be _really_ annoying to deal with. Have to deal with circular dependencies due to static module constructors which aren't actually interdependent is one of the most annoying issues in D IMHO.

- Jonathan M Davis
December 16, 2011
On 12/16/11 1:41 PM, Jonathan M Davis wrote:
> You could make core.time use property functions instead of the static
> immutable variables that it's using now for ticksPerSec and
> appOrigin, but in order to do that right would require introducing a
> mutex or synchronized block (which is really just a mutex under the
> hood anyway), and I'm loathe to do that in time-related code.
> ticksPerSec gets used all over the place in TickDuration, and that
> could have a negative impact on performance for something that needs
> to be really fast (since it's used in stuff like StopWatch and
> benchmarking). On top of that, in order to maintain the current
> semantics, the property functions would have to be pure, which they
> can't be without doing some nasty casting to convince the compiler
> that stuff which isn't pure is actually pure.
>
> For std.datetime, the problem would be reduced if a class could be
> created in CTFE and still be around at runtime, but we can't do that
> yet, and it wouldn't completely solve the problem, since the shared
> static constructor related to LocalTime has to call tzset. So, some
> sort of runtime initialization must be done. And the instances for
> the singleton are not only immutable, but the functions for getting
> them are pure. So, once again, some nasty casting would be required
> to get it to work without breaking purity. And once again, we'd have
> introduce a mutex. And for both core.time and std.datetime we're
> talking about a mutex would be needed only briefly to ensure that we
> don't end up with two threads trying to initialize the variable at
> the same time. After that, it would just be impeding performance for
> no value. They're classic situations for static constructors -
> initializing static immutable variables - and really, they _should_
> be using static constructors. If we have to get rid of them, it's to
> get around other problems in the language or compiler instead of
> fixing those problems. So, on some level, that seems like a failure
> on the part of the language and the compiler. If we _have_ to find a
> workaround, then we have to find a workaround, but I find the need to
> be distasteful to say the least. I previously tried to get rid of the
> static constructors in std.datetime and couldn't precisely because
> they're needed unless you play major casting games to get around
> immutable and pure.
>
> If we play nice, it's impossible to get rid of the static
> constructors in std.datetime. It probably is possible if we do nasty
> casting, but (much as I hate to use the word) it seems like this is a
> hack to get around the fact that the compiler isn't dealing with
> static constructors as well as we'd like. I'd _really_ like to see
> this fixed at the compiler level.

I understand and empathize with the sentiment, and I agree with most of the technical points at face value, save for a few details. But there are other things at stake.

Consider scope. Many arguments applicable to application code are not quite fit for the standard library. The stdlib is the connection between the compiler innards, the runtime innards, and the OS innards all meet, and the role of the stdlib is to provide nice abstractions to client code. Inside the stdlib it's entirely expected to find things like __traits most nobody heard of, casts, and other things that would be normally shunned in application code. I'd be more worried if there was no possibility to do what we need to do. The standard library is not a place to play it nice. We can't afford to say "well yeah everyone's binary is bloated and slower to start but we didn't like the cast that would have taken care of that".

As another matter, there is value in minimizing compulsive work during library startup. Consider for example this code in std.datetime:

    shared static this()
    {
        tzset();
        _localTime = new immutable(LocalTime)();
    }

This summons the garbage collector right off the bat, thus wiping off anyone's chance of compiling and linking without a GC - as many people seem to want to do. And that happens not to programs that import and use std.datetime, but to program using any part of the standard library that transitively imports std.datetime, even for the most innocuous uses, and even if they never, ever use _localtime! That one line essentially locks out 75% of the standard library to anyone wishing to ever avoid using the GC.

> And honestly, I think that a far worse problem with static
> constructors is circular dependencies. _That_ is something that
> needs to be addressed with regards to static constructors. In general
> at this point, it's looking like static constructors are turning out
> to be a bit of a failure on some level, given the issues that we're
> having because of them, and I think that we should fix the language
> and/or compiler so that they _aren't_ a failure.

Here I totally disagree. The design is sound. The issues discussed here are entirely detail implementation artifacts.


Andrei
December 16, 2011
On 2011-12-16 20:48, Andrei Alexandrescu wrote:
> On 12/16/11 1:23 PM, Steven Schveighoffer wrote:
>> I disagree with this assessment. It's good to know the cause of the
>> problem, but let's look at the root issue -- reflection. The only reason
>> to include class information for classes not being referenced is to be
>> able to construct/use classes at runtime instead of at compile time. But
>> if you look at D's runtime reflection capabilities, they are quite poor.
>> You can only construct a class at runtime if it has a zero-arg
>> constructor.
>>
>> So essentially, we are paying the penalty of having runtime reflection
>> in terms of bloat, but get very very little benefit.
>
> I'd almost agree, but the code showed doesn't use Object.factory(). So
> that shouldn't be linked in, and shouldn't pull vtables.

There are other runtime reflection functionality that can be used.

>> I think there are two things that need to be considered:
>>
>> 1. We eventually should have some reasonably complete runtime reflection
>> capability
>> 2. Runtime reflection and shared libraries go hand-in-hand. With shared
>> library support, the bloat penalty isn't nearly as significant.
>>
>> I don't think the right answer is to avoid using features of the
>> language because the compiler/runtime has some design deficiencies. At
>> some point these deficiencies will be fixed, and then we are left with a
>> library that has seemingly odd design choices that we can't change.
>
> Runtime reflection is great, but I think it's a separate issue from
> what's discussed here.

I don't think it's completely separate. Can the compiler know if runtime reflection is used or not?


-- 
/Jacob Carlborg
December 16, 2011
On 12/16/11 2:47 PM, Jacob Carlborg wrote:
> I don't think it's completely separate. Can the compiler know if runtime
> reflection is used or not?

Yes. Reflection is used if reflection primitive functions are called.

Andrei

« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10 11