www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Going from CTFE-land to Template-land

reply Bill Baxter <wbaxter gmail.com> writes:
Currently this doesn't work, because the CTFE function doesn't "know"
that it's running compile-time:

int templ_incr(int x)() {
    return x+1;
}

int ctfe_incr(int x) {
    return templ_incr!(x);
}

Seems common to write a function that you know is only intended to be
used compile-time.
But it can't compile because the compiler doesn't know you only plan
to call it at compile-time.

Is something version(__ctfe) might help with?  E.g.
version(__ctfe) {
    // only allow cfte_incr to be called at compile-time so it can use templates
    int ctfe_incr(int x) {
        return templ_incr!(x);
    }
}

Or is there something more fundamental preventing CTFE funcs from
instantiating templates?

--bb
Nov 17 2009
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 17 Nov 2009 08:14:55 -0500, Bill Baxter <wbaxter gmail.com> wrote:

 Currently this doesn't work, because the CTFE function doesn't "know"
 that it's running compile-time:

 int templ_incr(int x)() {
     return x+1;
 }

 int ctfe_incr(int x) {
     return templ_incr!(x);
 }

 Seems common to write a function that you know is only intended to be
 used compile-time.
 But it can't compile because the compiler doesn't know you only plan
 to call it at compile-time.

 Is something version(__ctfe) might help with?  E.g.
 version(__ctfe) {
     // only allow cfte_incr to be called at compile-time so it can use  
 templates
     int ctfe_incr(int x) {
         return templ_incr!(x);
     }
 }

 Or is there something more fundamental preventing CTFE funcs from
 instantiating templates?

I think it may be a valid point, but it also may be a case of factoring. Do you have a real example? In the one you posted, you can trivially rewrite ctfe_incr(x); as templ_incr!(x)(); // not sure if parens are optional there... or trivially rewrite ctfe_incr as: int ctfe_incr(int x) { return x + 1; } A real example would go a long way in furthering the cause... -Steve
Nov 17 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Nov 17, 2009 at 5:28 AM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 On Tue, 17 Nov 2009 08:14:55 -0500, Bill Baxter <wbaxter gmail.com> wrote=

 Currently this doesn't work, because the CTFE function doesn't "know"
 that it's running compile-time:

 int templ_incr(int x)() {
 =A0 =A0return x+1;
 }

 int ctfe_incr(int x) {
 =A0 =A0return templ_incr!(x);
 }

 Seems common to write a function that you know is only intended to be
 used compile-time.
 But it can't compile because the compiler doesn't know you only plan
 to call it at compile-time.

 Is something version(__ctfe) might help with? =A0E.g.
 version(__ctfe) {
 =A0 =A0// only allow cfte_incr to be called at compile-time so it can us=


 templates
 =A0 =A0int ctfe_incr(int x) {
 =A0 =A0 =A0 =A0return templ_incr!(x);
 =A0 =A0}
 }

 Or is there something more fundamental preventing CTFE funcs from
 instantiating templates?

I think it may be a valid point, but it also may be a case of factoring. =

 you have a real example? =A0In the one you posted, you can trivially rewr=

 ctfe_incr(x);

 as

 templ_incr!(x)(); // not sure if parens are optional there...

 or trivially rewrite ctfe_incr as:

 int ctfe_incr(int x) {
 =A0return x + 1;
 }

 A real example would go a long way in furthering the cause...

For instance there's a handy "Format!(A...)" template in std.metastrings. But it works on template arguments. So you can't call it from a CTFE funct= ion. Though, there the correct solution is probably "rewrite Format!() as a CTFE function". I don't really know if this is a fundamentally a limitation or not. But I would like to why not if it is not a problem. It just seems like an artificial barrier. If I prefer to write something as a template seems like I should be able to. Perhaps this is just something that should become an Effective D tip: always prefer CTFE over templates where possible. Templates also have the disadvantage of bloating up your binaries. A related thing is the inability to effectively use "pragma(msg, ...)" inside a ctfe function. (It's related in the sense that if you *could* instantiate a template from CTFE then you could make a template that calls pragma(msg,...) to print something useful). --bb
Nov 17 2009
prev sibling next sibling parent Don <nospam nospam.com> writes:
Bill Baxter wrote:
 Currently this doesn't work, because the CTFE function doesn't "know"
 that it's running compile-time:
 
 int templ_incr(int x)() {
     return x+1;
 }
 
 int ctfe_incr(int x) {
     return templ_incr!(x);
 }
 
 Seems common to write a function that you know is only intended to be
 used compile-time.
 But it can't compile because the compiler doesn't know you only plan
 to call it at compile-time.
 
 Is something version(__ctfe) might help with?  E.g.
 version(__ctfe) {
     // only allow cfte_incr to be called at compile-time so it can use
templates
     int ctfe_incr(int x) {
         return templ_incr!(x);
     }
 }

No. Here's the only functionality you'll get. This works by exploiting bug 1330. It's inefficient: the inCTFE function gets called all the time. Should just be a bool value, which will be constant-folded away. Otherwise, it's the same as this: // true if evaluated in CTFE, false if called at runtime. bool inCTFE() { int [1] x = [1]; int [] y = x; y[0] = 2; return x[0]!=2; } static assert(inCTFE()); void main() { assert(!inCTFE()); }
Nov 17 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 17 Nov 2009 18:07:03 +0300, Don <nospam nospam.com> wrote:

 Bill Baxter wrote:
 Currently this doesn't work, because the CTFE function doesn't "know"
 that it's running compile-time:
  int templ_incr(int x)() {
     return x+1;
 }
  int ctfe_incr(int x) {
     return templ_incr!(x);
 }
  Seems common to write a function that you know is only intended to be
 used compile-time.
 But it can't compile because the compiler doesn't know you only plan
 to call it at compile-time.
  Is something version(__ctfe) might help with?  E.g.
 version(__ctfe) {
     // only allow cfte_incr to be called at compile-time so it can use  
 templates
     int ctfe_incr(int x) {
         return templ_incr!(x);
     }
 }

No. Here's the only functionality you'll get. This works by exploiting bug 1330. It's inefficient: the inCTFE function gets called all the time. Should just be a bool value, which will be constant-folded away. Otherwise, it's the same as this: // true if evaluated in CTFE, false if called at runtime. bool inCTFE() { int [1] x = [1]; int [] y = x; y[0] = 2; return x[0]!=2; } static assert(inCTFE()); void main() { assert(!inCTFE()); }

Haha, nice one!
Nov 17 2009
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Nov 17, 2009 at 7:07 AM, Don <nospam nospam.com> wrote:
 Bill Baxter wrote:
 Currently this doesn't work, because the CTFE function doesn't "know"
 that it's running compile-time:

 int templ_incr(int x)() {
 =A0 =A0return x+1;
 }

 int ctfe_incr(int x) {
 =A0 =A0return templ_incr!(x);
 }

 Seems common to write a function that you know is only intended to be
 used compile-time.
 But it can't compile because the compiler doesn't know you only plan
 to call it at compile-time.

 Is something version(__ctfe) might help with? =A0E.g.
 version(__ctfe) {
 =A0 =A0// only allow cfte_incr to be called at compile-time so it can us=


 templates
 =A0 =A0int ctfe_incr(int x) {
 =A0 =A0 =A0 =A0return templ_incr!(x);
 =A0 =A0}
 }

No. Here's the only functionality you'll get. This works by exploiting bu=

 1330. It's inefficient: the inCTFE function gets called all the time. Sho=

 just be a bool value, which will be constant-folded away. Otherwise, it's
 the same as this:

 // true if evaluated in CTFE, false if called at runtime.
 bool inCTFE()
 {
 =A0 =A0 int [1] x =3D [1];
 =A0 =A0 int [] y =3D x;
 =A0 =A0 y[0] =3D 2;
 =A0 =A0 return x[0]!=3D2;
 }

 static assert(inCTFE());

 void main()
 {
 =A0assert(!inCTFE());
 }

After pondering it some more, I'm inclined to think CTFE->Template calls are not really needed. Templates are at their heart supposed to offer computations on types. Sometimes types involve values, so they need to be able to do some compute with values too. CTFE on the other hand is all about doing compute on values. So if you're in a CTFE function you're definitely in value-land. There shouldn't be any reason to need to pass your CTFE values to a template. By definition you're only dealing with values, so you don't need the type computation features of templates. --bb
Nov 17 2009