www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - :? in templates

reply Bill Baxter <wbaxter gmail.com> writes:
Didn't this used to work?

template factorial(int i) {
    enum factorial = (i==0) ? 1 : i*factorial!(i-1);
}

With DMD 2.036 I'm getting:
  Error: template instance factorial!(-495) recursive expansion

Seems like it expands both branches regardless of the condition.
And seems to me like it shouldn't.

--bb
Nov 18 2009
next sibling parent reply retard <re tard.com.invalid> writes:
Wed, 18 Nov 2009 03:10:57 -0800, Bill Baxter wrote:

 Didn't this used to work?
 
 template factorial(int i) {
     enum factorial = (i==0) ? 1 : i*factorial!(i-1);
 }
 
 With DMD 2.036 I'm getting:
   Error: template instance factorial!(-495) recursive expansion
 
 Seems like it expands both branches regardless of the condition. And
 seems to me like it shouldn't.

There's probably a confusion here. It evaluates lazily the value of factorial!(), but its type (which happens to be infinitely recursive must be evaluated eagerly in order to infer the type of the ternary op.
Nov 18 2009
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Bill Baxter wrote:
 On Wed, Nov 18, 2009 at 3:16 AM, retard <re tard.com.invalid> wrote:

 There's probably a confusion here. It evaluates lazily the value of
 factorial!(), but its type (which happens to be infinitely recursive must
 be evaluated eagerly in order to infer the type of the ternary op.

That makes sense. I guess the ?: op is defined to do that in all cases. Might be nice though if it didn't do that in cases where the condition was statically known.

That would lead to expressions changing type in unexpected circumstances. But what if we made it depend on whether the context requires a compile-time constant?
 Or if we just had a separate "static if" version of ?:

Maybe make ?? a compile-time version, which selects the type as well as the value? ("static ?" would also fit into the grammar without adding ambiguity, but I'm not sure that it looks as nice.) Stewart.
Nov 18 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Wed, Nov 18, 2009 at 3:16 AM, retard <re tard.com.invalid> wrote:
 Wed, 18 Nov 2009 03:10:57 -0800, Bill Baxter wrote:

 Didn't this used to work?

 template factorial(int i) {
 =A0 =A0 enum factorial =3D (i=3D=3D0) ? 1 : i*factorial!(i-1);
 }

 With DMD 2.036 I'm getting:
 =A0 Error: template instance factorial!(-495) recursive expansion

 Seems like it expands both branches regardless of the condition. And
 seems to me like it shouldn't.

There's probably a confusion here. It evaluates lazily the value of factorial!(), but its type (which happens to be infinitely recursive must be evaluated eagerly in order to infer the type of the ternary op.

That makes sense. I guess the ?: op is defined to do that in all cases. Might be nice though if it didn't do that in cases where the condition was statically known. Or if we just had a separate "static if" version of ?: --bb
Nov 18 2009
prev sibling next sibling parent Max Samukha <spambox d-coding.com> writes:
On Wed, 18 Nov 2009 03:10:57 -0800, Bill Baxter <wbaxter gmail.com>
wrote:

Didn't this used to work?

template factorial(int i) {
    enum factorial = (i==0) ? 1 : i*factorial!(i-1);
}

With DMD 2.036 I'm getting:
  Error: template instance factorial!(-495) recursive expansion

Seems like it expands both branches regardless of the condition.
And seems to me like it shouldn't.

--bb

While we are at it, binary logical operators has the same issue: static if (foo!() && bar!()) { } else { } bar is instantiated even if 'foo!()' results in false. To work around it, you have to add another 'static if' and duplicate the 'else' block: static if (foo!()) { static if (bar!()) { } else { } } else { } I've encountered the problem several times and would be happy to have it fixed, if possible.
Nov 18 2009
prev sibling next sibling parent retard <re tard.com.invalid> writes:
Wed, 18 Nov 2009 03:31:11 -0800, Bill Baxter wrote:

 On Wed, Nov 18, 2009 at 3:16 AM, retard <re tard.com.invalid> wrote:
 Wed, 18 Nov 2009 03:10:57 -0800, Bill Baxter wrote:

 Didn't this used to work?

 template factorial(int i) {
     enum factorial = (i==0) ? 1 : i*factorial!(i-1);
 }

 With DMD 2.036 I'm getting:
   Error: template instance factorial!(-495) recursive expansion

 Seems like it expands both branches regardless of the condition. And
 seems to me like it shouldn't.

There's probably a confusion here. It evaluates lazily the value of factorial!(), but its type (which happens to be infinitely recursive must be evaluated eagerly in order to infer the type of the ternary op.

That makes sense. I guess the ?: op is defined to do that in all cases. Might be nice though if it didn't do that in cases where the condition was statically known.

so int foo = (1==1) ? 6 : "haha"; would work, too? I think it would still need to check that the types of both branches match.
Nov 18 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Wed, Nov 18, 2009 at 3:36 AM, retard <re tard.com.invalid> wrote:
 Wed, 18 Nov 2009 03:31:11 -0800, Bill Baxter wrote:

 On Wed, Nov 18, 2009 at 3:16 AM, retard <re tard.com.invalid> wrote:
 Wed, 18 Nov 2009 03:10:57 -0800, Bill Baxter wrote:

 Didn't this used to work?

 template factorial(int i) {
 =A0 =A0 enum factorial =3D (i=3D=3D0) ? 1 : i*factorial!(i-1);
 }

 With DMD 2.036 I'm getting:
 =A0 Error: template instance factorial!(-495) recursive expansion

 Seems like it expands both branches regardless of the condition. And
 seems to me like it shouldn't.

There's probably a confusion here. It evaluates lazily the value of factorial!(), but its type (which happens to be infinitely recursive must be evaluated eagerly in order to infer the type of the ternary op.

That makes sense. =A0I guess the ?: op is defined to do that in all case=


 =A0Might be nice though if it didn't do that in cases where the conditio=


 was statically known.

so =A0int foo =3D (1=3D=3D1) ? 6 : "haha"; would work, too? I think it would still need to check that the types of both branches match.

Yeh, that could be confusing. Actually it would break a lot of code, too, now that I think of it. People use typeof(true?a:b) to get the common type. That's why it probably needs to be a distinct thing, a static ?:. --bb
Nov 18 2009
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 18 Nov 2009 14:50:42 +0300, Bill Baxter <wbaxter gmail.com> wrote:

 On Wed, Nov 18, 2009 at 3:36 AM, retard <re tard.com.invalid> wrote:
 Wed, 18 Nov 2009 03:31:11 -0800, Bill Baxter wrote:

 On Wed, Nov 18, 2009 at 3:16 AM, retard <re tard.com.invalid> wrote:
 Wed, 18 Nov 2009 03:10:57 -0800, Bill Baxter wrote:

 Didn't this used to work?

 template factorial(int i) {
     enum factorial = (i==0) ? 1 : i*factorial!(i-1);
 }

 With DMD 2.036 I'm getting:
   Error: template instance factorial!(-495) recursive expansion

 Seems like it expands both branches regardless of the condition. And
 seems to me like it shouldn't.

There's probably a confusion here. It evaluates lazily the value of factorial!(), but its type (which happens to be infinitely recursive must be evaluated eagerly in order to infer the type of the ternary op.

That makes sense. I guess the ?: op is defined to do that in all cases. Might be nice though if it didn't do that in cases where the condition was statically known.

so int foo = (1==1) ? 6 : "haha"; would work, too? I think it would still need to check that the types of both branches match.

Yeh, that could be confusing. Actually it would break a lot of code, too, now that I think of it. People use typeof(true?a:b) to get the common type. That's why it probably needs to be a distinct thing, a static ?:. --bb

The simplest solution is probably to give the compiler a hint: enum foo = someStaticCondition ? cast(Foo)SomeTemplate!() : cast(Foo)SomeOtherTemplate!(); Looks a bit hackish (and doesn't currently work), though.
Nov 18 2009