www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Non compile time evaluation for initializers

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
Is there a good reason why the compiler does not allow non-CTFE initializers 
for non-const variables?

For instance, this does not work:

Logger log = Log.getLogger("test");

but this does:

Logger log;
static this()
{
   log = Log.getLogger("test");
}

But why is it necessary to prevent the first from compiling to the 
equivalent of the second?  As far as I'm concerned, it's OK if it doesn't 
evaluate at compile time.  And it's much more convenient to write the first 
version when you are setting up global or static variables instead of using 
the static this() form.  In my mind, CTFE is a form of optimization, one 
which I can live without if it's not possible, but I still want to be able 
to compile :)

-Steve 
Oct 25 2007
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
news:ffquc2$2kjg$1 digitalmars.com...
 Is there a good reason why the compiler does not allow non-CTFE 
 initializers for non-const variables?

 For instance, this does not work:

 Logger log = Log.getLogger("test");

 but this does:

 Logger log;
 static this()
 {
   log = Log.getLogger("test");
 }

I agree. Java and C# allow this, and I think it fits in very nicely with the existing static constructors. Since you can have multiple static constructors in a module which are just executed in lexical order, a static variable being initialized with a non-compile-time initializer could just be rewritten as a declaration + 1-line static constructor. Basically, your first snippet would be converted into your second.
Oct 25 2007
prev sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 10/25/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 Is there a good reason why the compiler does not allow non-CTFE initializers
 for non-const variables?

So you're saying that, in general, if X x = y; won't compile, then the compiler should rewrite it as X x; static this { x = y; } Makes sense to me!
Oct 25 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On 10/25/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 Is there a good reason why the compiler does not allow non-CTFE initializers
 for non-const variables?

So you're saying that, in general, if X x = y; won't compile, then the compiler should rewrite it as X x; static this { x = y; } Makes sense to me!

I think that's only the case for X x being static in the first place. So static X x = y; is rewritten static X x; static this { x = y; } For class members I guess you might have the non-static initializers turn into some hidden extra work done just before the class's this() constructor. I don't know if it's a good plan or not, but it would certainly be a lot nicer to be able to do: class x { int[] buffer = new int[128]; ... } instead of: class x { int[] buffer; this() { buffer = new int[128]; } this(Arg a) { this(); } this(OtherArg a) { this(); } } I seem to recall that Java allows that. --bb
Oct 26 2007
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Bill Baxter wrote:
 Janice Caron wrote:
 On 10/25/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 Is there a good reason why the compiler does not allow non-CTFE 
 initializers
 for non-const variables?

So you're saying that, in general, if X x = y; won't compile, then the compiler should rewrite it as X x; static this { x = y; } Makes sense to me!

I think that's only the case for X x being static in the first place. So static X x = y; is rewritten static X x; static this { x = y; }

Ignore that part. I think I was thinking about class X x being a class member. so class Foo { static X x = y; } becomes class Foo { static X x; } static this { Foo.x = y; } --bb
Oct 26 2007
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Bill Baxter" wrote
 I think that's only the case for X x being static in the first place.

Yes, that was my intention. I was not thinking about instance members, as those could be a significant performance hit if you evaluate the rvalue at runtime every time an instance is created.
 For class members I guess you might have the non-static initializers turn 
 into some hidden extra work done just before the class's this() 
 constructor.

 I don't know if it's a good plan or not, but it would certainly be a lot 
 nicer to be able to do:

 class x
 {
    int[] buffer = new int[128];
    ...
 }

 instead of:

 class x
 {
    int[] buffer;

    this() {
       buffer = new int[128];
    }
    this(Arg a) {
       this();
    }
    this(OtherArg a) {
       this();
    }
 }

Yeah, it does seem like that would be useful. I purposely did not include instance members because I couldn't think of a good example to explain why you would always initialize a variable the same way. Your example not only demonstrates that point, but it is probably a very common one. I think as long as the user is made aware through documentation that the rvalue could be evaluated every time an object is constructed, it would be a good thing to have. -Steve
Oct 29 2007
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Janice Caron wrote:
 On 10/25/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 Is there a good reason why the compiler does not allow non-CTFE initializers
 for non-const variables?

So you're saying that, in general, if X x = y; won't compile, then the compiler should rewrite it as X x; static this { x = y; } Makes sense to me!

Suppose this is implemented, then how can you achieve constant folding with CTFE in initializers? Since it is not a compile time context anymore, all functions that substitue y will be evaluated at runtime.
Oct 26 2007
parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Lutger wrote:
 Janice Caron wrote:

 Suppose this is implemented, then how can you achieve constant folding 
 with CTFE in initializers? Since it is not a compile time context 
 anymore, all functions that substitue y will be evaluated at runtime.

Nevermind, I responded too soon and overlooked the proviso that it's only rewritten when it doesn't compile, sorry.
Oct 26 2007
parent reply Max Samukha <samukha voliacable.com.removethis> writes:
On Fri, 26 Oct 2007 10:52:25 +0200, Lutger
<lutger.blijdestijn gmail.com> wrote:

Lutger wrote:
 Janice Caron wrote:

 Suppose this is implemented, then how can you achieve constant folding 
 with CTFE in initializers? Since it is not a compile time context 
 anymore, all functions that substitue y will be evaluated at runtime.

Nevermind, I responded too soon and overlooked the proviso that it's only rewritten when it doesn't compile, sorry.

Then if a compile time function is messed up in a way that makes it unevaluatable at compile time, it would be silently used at run-time, which is not desired?
Oct 26 2007
next sibling parent reply Reiner Pope <some address.com> writes:
Max Samukha wrote:
 On Fri, 26 Oct 2007 10:52:25 +0200, Lutger
 <lutger.blijdestijn gmail.com> wrote:
 
 Lutger wrote:
 Janice Caron wrote:

 Suppose this is implemented, then how can you achieve constant folding 
 with CTFE in initializers? Since it is not a compile time context 
 anymore, all functions that substitue y will be evaluated at runtime.

only rewritten when it doesn't compile, sorry.

Then if a compile time function is messed up in a way that makes it unevaluatable at compile time, it would be silently used at run-time, which is not desired?

There are plenty of other ways to force compile-time evaluation. I use const int x = ctfeFunction(); much more than // global namespace int x = ctfeFunction(); I wouldn't have any objection to keeping const meaning ctfe-evaluated, but global non-consts may be postponed till runtime. -- Reiner
Oct 26 2007
parent Max Samukha <samukha voliacable.com.removethis> writes:
On Fri, 26 Oct 2007 22:47:02 +1000, Reiner Pope <some address.com>
wrote:

There are plenty of other ways to force compile-time evaluation. I use

const int x = ctfeFunction();

much more than

// global namespace
int x = ctfeFunction();


I wouldn't have any objection to keeping const meaning ctfe-evaluated, 
but global non-consts may be postponed till runtime.


   -- Reiner

Agree
Oct 26 2007
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Max Samukha wrote:
 On Fri, 26 Oct 2007 10:52:25 +0200, Lutger
 <lutger.blijdestijn gmail.com> wrote:
 
 Lutger wrote:
 Janice Caron wrote:

 Suppose this is implemented, then how can you achieve constant folding 
 with CTFE in initializers? Since it is not a compile time context 
 anymore, all functions that substitue y will be evaluated at runtime.

only rewritten when it doesn't compile, sorry.

Then if a compile time function is messed up in a way that makes it unevaluatable at compile time, it would be silently used at run-time, which is not desired?

Hmm yes, it's still an issue. Some functions are quite inefficient for example if they are made to be evaluated at compile time, which doesn't matter in that context but does for the runtime case.
Oct 26 2007
parent reply Max Samukha <samukha voliacable.com.removethis> writes:
On Fri, 26 Oct 2007 15:45:45 +0200, Lutger
<lutger.blijdestijn gmail.com> wrote:

Max Samukha wrote:
 On Fri, 26 Oct 2007 10:52:25 +0200, Lutger
 <lutger.blijdestijn gmail.com> wrote:
 
 Lutger wrote:
 Janice Caron wrote:

 Suppose this is implemented, then how can you achieve constant folding 
 with CTFE in initializers? Since it is not a compile time context 
 anymore, all functions that substitue y will be evaluated at runtime.

only rewritten when it doesn't compile, sorry.

Then if a compile time function is messed up in a way that makes it unevaluatable at compile time, it would be silently used at run-time, which is not desired?

Hmm yes, it's still an issue. Some functions are quite inefficient for example if they are made to be evaluated at compile time, which doesn't matter in that context but does for the runtime case.

As Reiner mentioned, the problem is that static variables should not be initialized at compile-time at all. If you want CTFE put the initializers in const context. int foo() { return 1; } static int x = foo; // module scope, static is optional; foo would be evaluated on module construction class C { static x = foo; // ditto } void bar() { static x = foo; // ditto } Then 'static' keyword here would mean 'global' and compile time constructs would have to be changed to 'const if', 'const assert', etc (Don't beat me please!)
Oct 26 2007
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Max Samukha" wrote
 On Fri, 26 Oct 2007 15:45:45 +0200, Lutger
 <lutger.blijdestijn gmail.com> wrote:

Max Samukha wrote:
 On Fri, 26 Oct 2007 10:52:25 +0200, Lutger
 <lutger.blijdestijn gmail.com> wrote:

 Lutger wrote:
 Janice Caron wrote:

 Suppose this is implemented, then how can you achieve constant folding
 with CTFE in initializers? Since it is not a compile time context
 anymore, all functions that substitue y will be evaluated at runtime.

only rewritten when it doesn't compile, sorry.

Then if a compile time function is messed up in a way that makes it unevaluatable at compile time, it would be silently used at run-time, which is not desired?

Hmm yes, it's still an issue. Some functions are quite inefficient for example if they are made to be evaluated at compile time, which doesn't matter in that context but does for the runtime case.

As Reiner mentioned, the problem is that static variables should not be initialized at compile-time at all. If you want CTFE put the initializers in const context. int foo() { return 1; } static int x = foo; // module scope, static is optional; foo would be evaluated on module construction class C { static x = foo; // ditto } void bar() { static x = foo; // ditto } Then 'static' keyword here would mean 'global' and compile time constructs would have to be changed to 'const if', 'const assert', etc (Don't beat me please!)

I'm not sure that const = CTFE/static = runtime is the right answer. My original idea was that the compiler would decide if it could evaluate the rvalue at compile time, and do so if possible, but if not possible, use a static constructor to initialize the variable. The current behavior is to have a compile-time error. I understand your concern that when a CTFE is desired, you will not be able to tell whether the compiler decided to do it or not, but in all cases I can think of: 1. if you don't get CTFE, the evaluation is only a 1 time hit, at the beginning of the program. 2. If the compiler can't do CTFE, then it's probably because the rvalue cannot be evaluated at compile time no matter how you code it. 3. Most of the time, the static constructor form is what you really meant, but the compiler is forcing you to type it out that way. To address this concern, could there be some sort of compile message, like a pragma that tells the compiler it should be able to do CTFE on an rvalue? -Steve
Oct 29 2007