| Thread overview | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
September 20, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
On Thu, 20 Sep 2012 23:22:36 +0200, Jens Mueller <jens.k.mueller@gmx.de> wrote: > string foo(string f) > { > if (f == "somestring") > { > return "got somestring"; > } > return bar!(foo("somestring")); > } > > template bar(string s) > { > enum bar = s; > } > In line 7 I call the template bar. But I call with the string that is > returned by the CTFE of foo("somestring") which should return "got > somestring" When's it gonna get around to doing that? In order to figure out the return value of foo("somestring"), it will have to figure out the return value of foo("somestring"), and to do that... > I haven't found a bug on this. That's because there is no bug. -- Simen | ||||
September 20, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
On Thursday, September 20, 2012 23:22:36 Jens Mueller wrote:
> Hi,
>
> I do not understand the following error message given the code:
>
> string foo(string f)
> {
> if (f == "somestring")
> {
> return "got somestring";
> }
> return bar!(foo("somestring"));
> }
>
> template bar(string s)
> {
> enum bar = s;
> }
>
> I'll with dmd v2.060 get:
> test.d(7): called from here: foo("somestring")
> test.d(7): called from here: foo("somestring")
> test.d(7): called from here: foo("somestring")
> test.d(7): Error: expression foo("somestring") is not a valid template value
> argument test.d(12): called from here: foo("somestring")
> test.d(12): called from here: foo("somestring")
> test.d(7): Error: template instance test.bar!(foo("somestring")) error
> instantiating
>
> In line 7 I call the template bar. But I call with the string that is
> returned by the CTFE of foo("somestring") which should return "got
> somestring" but instead it seems that an expression is passed. How do I
> force the evaluation foo("somestring")?
> I haven't found a bug on this.
Template arguments must be known at compile time. And even if you use foo at compile time, it has to be compiled before you use it, so you can't call it inside itself and pass that as a template argument. foo must be fully compiled before it can be called, and as it stands, it can't be fully compiled until it's called. So... Yeah. Not going to work.
- Jonathan M Davis
| ||||
September 20, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
Simen Kjaeraas wrote:
> On Thu, 20 Sep 2012 23:22:36 +0200, Jens Mueller <jens.k.mueller@gmx.de> wrote:
>
> >string foo(string f)
> >{
> > if (f == "somestring")
> > {
> > return "got somestring";
> > }
> > return bar!(foo("somestring"));
> >}
> >
> >template bar(string s)
> >{
> > enum bar = s;
> >}
>
> >In line 7 I call the template bar. But I call with the string that is returned by the CTFE of foo("somestring") which should return "got somestring"
>
> When's it gonna get around to doing that? In order to figure out the
> return value of foo("somestring"), it will have to figure out the
> return value of foo("somestring"), and to do that...
There is no endless recursion. Note that foo("somestring") returns "got
somestring".
Am I wrong?
Jens
| ||||
September 20, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
Jonathan M Davis wrote:
> On Thursday, September 20, 2012 23:22:36 Jens Mueller wrote:
> > Hi,
> >
> > I do not understand the following error message given the code:
> >
> > string foo(string f)
> > {
> > if (f == "somestring")
> > {
> > return "got somestring";
> > }
> > return bar!(foo("somestring"));
> > }
> >
> > template bar(string s)
> > {
> > enum bar = s;
> > }
> >
> > I'll with dmd v2.060 get:
> > test.d(7): called from here: foo("somestring")
> > test.d(7): called from here: foo("somestring")
> > test.d(7): called from here: foo("somestring")
> > test.d(7): Error: expression foo("somestring") is not a valid template value
> > argument test.d(12): called from here: foo("somestring")
> > test.d(12): called from here: foo("somestring")
> > test.d(7): Error: template instance test.bar!(foo("somestring")) error
> > instantiating
> >
> > In line 7 I call the template bar. But I call with the string that is
> > returned by the CTFE of foo("somestring") which should return "got
> > somestring" but instead it seems that an expression is passed. How do I
> > force the evaluation foo("somestring")?
> > I haven't found a bug on this.
>
> Template arguments must be known at compile time. And even if you use foo at compile time, it has to be compiled before you use it, so you can't call it inside itself and pass that as a template argument. foo must be fully compiled before it can be called, and as it stands, it can't be fully compiled until it's called. So... Yeah. Not going to work.
I thought foo is interpreted at compile time.
There seems to be a subtle difference I'm not getting.
Because you can do the factorial using CTFE even though you have
recursion. I.e. there you have a call to the function itself. I.e. it
can be compiled because you just insert a call to the function. But for
a template you cannot issue something like call for instantiation.
Have to think more about it. But your answer helps a lot. Pushes me in
the right direction.
Jens
| ||||
September 20, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
On Friday, September 21, 2012 00:11:51 Jens Mueller wrote:
> I thought foo is interpreted at compile time.
> There seems to be a subtle difference I'm not getting.
> Because you can do the factorial using CTFE even though you have
> recursion. I.e. there you have a call to the function itself. I.e. it
> can be compiled because you just insert a call to the function. But for
> a template you cannot issue something like call for instantiation.
> Have to think more about it. But your answer helps a lot. Pushes me in
> the right direction.
Okay. Straight up recursion works. So, with this code
int func(int value)
{
if(value < 10)
return func(value + 1);
return value;
}
enum var = func(5);
var would be 10. The problem is that you're trying to pass the result of a recursive call as a template argument. As far as a function's behavior goes, it's identical regardless of whether it's run at compile time or runtime (save that __ctfe is true at compile time but not runtime). To quote the docs:
------
Any functions that execute at compile time must also be executable at run time. The compile time evaluation of a function does the equivalent of running the function at run time. This means that the semantics of a function cannot depend on compile time values of the function. For ex ample:
int foo(char[] s) {
return mixin(s);
}
const int x = foo("1");
is illegal, because the runtime code for foo() cannot be generated. A function template would be the appropriate method to implement this sort of thing.
------
You're doing something very similar to passing a function argument to a mixin statement, but in this case, it's passing the result of calling a function which doesn't exist yet (since it hasn't been fully compiled) to a template.
In order for your foo function to be called, it must be fully compiled first (including its entire body, since CTFE needs the full definition of the function, not just its signature). The body cannot be fully compiled until the template that it's using is instantiated. But that template can't be compiled until foo has been compiled, because you're passing a call to foo to it as a template argument. So, you have a circular dependency.
Normal recursion avoids this, because it only depends on the function's signature, but what you're doing requires that the function be _run_ as part of the process of defining it. That's an unbreakable circular dependency and will never work. You need to redesign your code so that you don't require a function to call itself while it's being defined. Being called at compile time is fine, but being called while it's being compiled is not.
- Jonathan M Davis
| ||||
September 20, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
On Friday, September 21, 2012 00:29:48 Jonathan M Davis wrote:
> As far as a function's behavior goes,
> it's identical regardless of whether it's run at compile time or runtime
> (save that __ctfe is true at compile time but not runtime).
Actually, that's not quite true (though it's very close). There are a couple of quirks such as the precision of floating point arithmetic differing and the exact value of NaN potentially being different (since there are multiple NaN values), but it's almost entirely true.
- Jonathan M Davis
| ||||
September 20, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 09/21/2012 12:29 AM, Jonathan M Davis wrote:
> ...
> In order for your foo function to be called, it must be fully compiled first
> (including its entire body, since CTFE needs the full definition of the
> function, not just its signature). The body cannot be fully compiled until the
> template that it's using is instantiated. But that template can't be compiled
> until foo has been compiled, because you're passing a call to foo to it as a
> template argument. So, you have a circular dependency.
>
> Normal recursion avoids this, because it only depends on the function's
> signature, but what you're doing requires that the function be _run_ as part
> of the process of defining it. That's an unbreakable circular dependency and
> will never work. ...
It is not exactly unbreakable. This can work. Just delay spitting out
an error to the point the execution actually depends upon its own
result.
| |||
September 21, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
Jonathan M Davis wrote: > On Friday, September 21, 2012 00:11:51 Jens Mueller wrote: > > I thought foo is interpreted at compile time. > > There seems to be a subtle difference I'm not getting. > > Because you can do the factorial using CTFE even though you have > > recursion. I.e. there you have a call to the function itself. I.e. it > > can be compiled because you just insert a call to the function. But for > > a template you cannot issue something like call for instantiation. > > Have to think more about it. But your answer helps a lot. Pushes me in > > the right direction. > > Okay. Straight up recursion works. So, with this code > > int func(int value) > { > if(value < 10) > return func(value + 1); > return value; > } > > enum var = func(5); > > var would be 10. The problem is that you're trying to pass the result of a recursive call as a template argument. As far as a function's behavior goes, it's identical regardless of whether it's run at compile time or runtime (save that __ctfe is true at compile time but not runtime). To quote the docs: > > ------ > Any functions that execute at compile time must also be executable at run time. The compile time evaluation of a function does the equivalent of running the function at run time. This means that the semantics of a function cannot depend on compile time values of the function. For ex ample: > > int foo(char[] s) { > return mixin(s); > } > > const int x = foo("1"); > > is illegal, because the runtime code for foo() cannot be generated. A function template would be the appropriate method to implement this sort of thing. > ------ Is it also illegal to do int foo(char[] s) { if (__ctfe) return mixin(s); else return ""; // or assert(false) } ? Because this is executable at run time. > You're doing something very similar to passing a function argument to a mixin statement, but in this case, it's passing the result of calling a function which doesn't exist yet (since it hasn't been fully compiled) to a template. > > In order for your foo function to be called, it must be fully compiled first (including its entire body, since CTFE needs the full definition of the function, not just its signature). The body cannot be fully compiled until the template that it's using is instantiated. But that template can't be compiled until foo has been compiled, because you're passing a call to foo to it as a template argument. So, you have a circular dependency. I see. That's is clear to me now. Thanks. > Normal recursion avoids this, because it only depends on the function's signature, but what you're doing requires that the function be _run_ as part of the process of defining it. That's an unbreakable circular dependency and will never work. You need to redesign your code so that you don't require a function to call itself while it's being defined. Being called at compile time is fine, but being called while it's being compiled is not. But if the function wasn't compiled but interpreted at compile time it would be possible, wouldn't it? Jens | ||||
September 21, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
Jens Mueller wrote:
> Jonathan M Davis wrote:
> > On Friday, September 21, 2012 00:11:51 Jens Mueller wrote:
> > > I thought foo is interpreted at compile time.
> > > There seems to be a subtle difference I'm not getting.
> > > Because you can do the factorial using CTFE even though you have
> > > recursion. I.e. there you have a call to the function itself. I.e. it
> > > can be compiled because you just insert a call to the function. But for
> > > a template you cannot issue something like call for instantiation.
> > > Have to think more about it. But your answer helps a lot. Pushes me in
> > > the right direction.
> >
> > Okay. Straight up recursion works. So, with this code
> >
> > int func(int value)
> > {
> > if(value < 10)
> > return func(value + 1);
> > return value;
> > }
> >
> > enum var = func(5);
> >
> > var would be 10. The problem is that you're trying to pass the result of a recursive call as a template argument. As far as a function's behavior goes, it's identical regardless of whether it's run at compile time or runtime (save that __ctfe is true at compile time but not runtime). To quote the docs:
> >
> > ------
> > Any functions that execute at compile time must also be executable at run time. The compile time evaluation of a function does the equivalent of running the function at run time. This means that the semantics of a function cannot depend on compile time values of the function. For ex ample:
> >
> > int foo(char[] s) {
> > return mixin(s);
> > }
> >
> > const int x = foo("1");
> >
> > is illegal, because the runtime code for foo() cannot be generated. A function template would be the appropriate method to implement this sort of thing.
> > ------
>
> Is it also illegal to do
>
> int foo(char[] s) {
> if (__ctfe)
> return mixin(s);
> else
> return ""; // or assert(false)
> }
>
> ?
>
> Because this is executable at run time.
Just read the docs again. And __ctfe is used to exclude running code at runtime. It seems it really is a variable that is false at runtime. I thought it more a value known at compile time. But then you would write static if anyway.
Somehow I find these restrictions unnecessary. I believe they can be solved. Then you could combine CTFE with all other compile-time mechanisms. But this needs more time to think about. Currently I will try to work around this. Let's see ...
Jens
| ||||
September 21, 2012 Re: CTFE calling a template: Error: expression ... is not a valid template value argument | ||||
|---|---|---|---|---|
| ||||
On Friday, September 21, 2012 10:44:11 Jens Mueller wrote: > Is it also illegal to do > > int foo(char[] s) { > if (__ctfe) > return mixin(s); > else > return ""; // or assert(false) > } > > ? > > Because this is executable at run time. It's not executable at runtime. The __ctfe branch may very well be optimized out when compiled for runtime, but that doesn't mean that the code in it can be invalid. The function must be fully compiled in either case. Removing the __ctfe branch would merely be an optimization. It's an if after all, not a static if (and __ctfe can't be used in static if). > > Normal recursion avoids this, because it only depends on the function's signature, but what you're doing requires that the function be _run_ as part of the process of defining it. That's an unbreakable circular dependency and will never work. You need to redesign your code so that you don't require a function to call itself while it's being defined. Being called at compile time is fine, but being called while it's being compiled is not. > > But if the function wasn't compiled but interpreted at compile time it would be possible, wouldn't it? D isn't an intepreted language, and I expect that trying to treat it at such would complicate things considerably. All CTFE does is make it possible to run functions at compile time in order to initialize stuff which must be known at compile time (which does include the possibility of doing stuff like passing function results as template arguments). It doesn't fundamentally change how things work. If anything, it's _more_ restrictive, not less. So, I don't think that it makes any sense at all to try and make it act in an interpretive fashion. - Jonathan M Davis | ||||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply