digitalmars.D - Proposal: static template(fail)
- Janice Caron (21/21) Dec 13 2007 I would like to propose a new statement:
- Aziz K. (1/1) Dec 13 2007 Why not use a static assert: static assert(0, "Substitution Failure");
- Janice Caron (10/11) Dec 13 2007 A static assert is a compile error. Different thing. What you want is
- Jason House (4/19) Dec 13 2007 I'd prefer a static assert.
- Janice Caron (38/59) Dec 13 2007 You're missing the point, which is IT'S NOT AN ERROR. It's a
- Ary Borenszweig (3/26) Dec 13 2007 I don't understand how it's not an error if you can't instantiate the
- Gregor Richards (3/30) Dec 13 2007 Because it could potentially instantiate a different (overloaded) templa...
- Rioshin an'Harthen (19/45) Dec 13 2007 It should *not* be an error of the template that a certain call can't
- Jason House (3/6) Dec 13 2007 That's certainly true in C++, but I was not aware that was the way D tem...
- Janice Caron (7/8) Dec 13 2007 But then you'd have to do
- Jason House (12/19) Dec 13 2007 You can do the following for something so simple
- Janice Caron (13/17) Dec 13 2007 It's a choice. It happens to be my /preferred/ choice, but the
- Jason House (10/22) Dec 14 2007 After reflecting, I agree. What I'd been talking about assumes a mostly...
- BCS (27/43) Dec 14 2007 the problem with static if is that it turns into a work-or-die-hard solu...
- Janice Caron (15/34) Dec 14 2007 I don't know if this is reasonable, because you've got multiple
- BCS (26/65) Dec 14 2007 That only works if the maintainers of the two templates work together. H...
- Janice Caron (12/14) Dec 14 2007 Gotcha. Well, it seems doable, so long as there is zero chance of
- BCS (6/25) Dec 14 2007 I think that would be preferable in some ways because it would place the...
- Christopher Wright (13/44) Dec 14 2007 Static import for the win!
- BCS (23/71) Dec 14 2007 Garsh Darn It!!! while that doesn't even get close to doing what I wante...
- BCS (3/29) Dec 13 2007 vote++
- Gregor Richards (5/39) Dec 13 2007 static template(fail) seems a bit more general purpose so probably
- Janice Caron (7/9) Dec 13 2007 Hey, we always argue about the syntax. It's a tradition! :-)
- Leandro Lucarella (10/21) Dec 13 2007 template break? =)
- Dejan Lekic (1/1) Dec 13 2007 Yes, idea is good, but proposed syntax is bad.
- Bill Baxter (4/30) Dec 13 2007 All you need is *anything* that would generate an ordinary compiler
- Janice Caron (2/4) Dec 13 2007 The idea is /not/ to generate a compiler error. :-)
- Bill Baxter (6/11) Dec 13 2007 Right, and it won't because as you've been reiterating "substitution
- Janice Caron (2/5) Dec 13 2007 Really? Wow! I'm going to have to try that now!
- Bruce Adams (4/9) Dec 13 2007 So did it work?
- Robert DaSilva (2/14) Dec 13 2007 I've tried it and it didn't work for me.
- Janice Caron (14/15) Dec 13 2007 I didn't think it would.
- Bruce Adams (8/23) Dec 14 2007 You've just added our old friend the backtracking algorithm.
- Jason House (2/11) Dec 14 2007 IMHO, this should have been part of the original post. Your suggestion ...
- BCS (12/12) Dec 14 2007 what would this do?:
- Bruce Adams (5/17) Dec 14 2007 I'm not so sure about that. Its a bit like saying he wouldn't like you t...
- BCS (3/26) Dec 14 2007 I'm taking about DMD's performance. The compile time cost of find a temp...
- Bruce Adams (13/38) Dec 14 2007 Prolog is entirely based on backtracking huge numbers of predicates and ...
- BCS (9/47) Dec 17 2007 take a look at scrapple.backmath, the bulk of it is a huge list of stati...
- Bruce Adams (7/27) Dec 17 2007 That is only the case if it is a programming style that is encouraged or
- BCS (5/14) Dec 18 2007 take that last bit out of context and you have just stated my concern. B...
- Bill Baxter (3/16) Dec 14 2007 Why be so cryptic? Show us what you tried for goodness sake.
- Bill Baxter (60/79) Dec 14 2007 Ok so I tried it myself. Apparently neither D nor C++ works the way I
- BCS (5/11) Dec 14 2007 The body of a template must be syntactically correct no matter what. If ...
- Sean Kelly (12/38) Dec 13 2007 I guess this would require the compiler to not complain if I did this?
- Bill Baxter (5/50) Dec 13 2007 No, you have to make one of them specialized somehow, otherwise it's
- Sean Kelly (4/51) Dec 13 2007 So either way I'd need to use specialization? I suppose this would
- Janice Caron (8/11) Dec 13 2007 I agree. But in the particular example you cited, you could instead just...
- Aziz K. (27/27) Dec 14 2007 I thought about this issue a little bit before I went to sleep yesterday...
I would like to propose a new statement: static template(fail); which causes a compile-time substitution failure. And remember: SFINAE - Substitution Failure Is Not An Error Let me give you an example: struct S(T) { static if(isFloatingPoint!(T)) { /*...*/ } else static if(passesSomeVeryComplicatedTest!(T)) { /*...*/ } else { static template(fail); // SFINAE } } This has advantages over old-style specialisation.
Dec 13 2007
Why not use a static assert: static assert(0, "Substitution Failure");
Dec 13 2007
On 12/13/07, Aziz K. <aziz.kerim gmail.com> wrote:Why not use a static assert: static assert(0, "Substitution Failure");A static assert is a compile error. Different thing. What you want is for the template not to be instanted, not for it to be instantiated with a compile error. Put it another way. Suppose you write S(int) s; Which would you prefer - an error message saying that s couldn't be instantiated (giving the filename and line number of the above line), or an error message saying that a static assert in the middle of some library file had been hit?
Dec 13 2007
Janice Caron Wrote:On 12/13/07, Aziz K. <aziz.kerim gmail.com> wrote:I'd prefer a static assert. As with all errors, I'd want a backtrace. Functions currently have in/body/out sections. I wouldn't mind seeing something like an "in" function for templated objects. To me, that's much more generic. In a world without backtraces for errors, it'd also allow a hint to the compiler that it should point the finger at the code that caused the instantiation.Why not use a static assert: static assert(0, "Substitution Failure");A static assert is a compile error. Different thing. What you want is for the template not to be instanted, not for it to be instantiated with a compile error. Put it another way. Suppose you write S(int) s; Which would you prefer - an error message saying that s couldn't be instantiated (giving the filename and line number of the above line), or an error message saying that a static assert in the middle of some library file had been hit?
Dec 13 2007
On 12/13/07, Jason House <jason.james.house gmail.com> wrote:Janice Caron Wrote:You're missing the point, which is IT'S NOT AN ERROR. It's a substitution failure - and substitution failure IS NOT AN ERROR. That's a basic principle of template programming. Look, right now you can do: template A(T:U) { /*code*/ } template A(T:V) { /*the same code*/ } template A(T:W) { /*the same code*/ } template A(T:X) { /*the same code*/ } template A(T:Y) { /*the same code*/ } but you can't simplify it as: template A(T:U|V|W|X|Y) What you /could/ do is: template A(T) { static if(is(T:U) | is(T:V) | is(T:W) | is(T:X) | is(T:y)) { /*code*/ } but you can't take the obvious next step of else substitution failure ...you have to make it an actual error. Template specialisation is a powerful tool in metaprogramming, but right now we have to use multiple specialisations in order to use it. We've got "static if" to move us away from that antiquated C++ model, but still the only way to generate a substitution failure is to go back to that model. Note that an alternative way to achieve much the same thing would be to extend the syntax of specialisation to include something like (T:if(expression)) where the specialisation is deemed to hold if the expression evaluates to true at compile time. I quite like that - but I like my first suggestion more. (Of course, they're not mutually exclusive).On 12/13/07, Aziz K. <aziz.kerim gmail.com> wrote:I'd prefer a static assert. As with all errors, I'd want a backtrace.Why not use a static assert: static assert(0, "Substitution Failure");A static assert is a compile error. Different thing. What you want is for the template not to be instanted, not for it to be instantiated with a compile error. Put it another way. Suppose you write S(int) s; Which would you prefer - an error message saying that s couldn't be instantiated (giving the filename and line number of the above line), or an error message saying that a static assert in the middle of some library file had been hit?Functions currently have in/body/out sections. I wouldn't mind seeing something like an "in" function for templated objects.Right - so like my second suggestion: template A(T:if(someTest!(T)))To me, that's much more generic.I'd say they're equivalent. It's just a question of whether you like to read if/else style code, or multiple specialisation style code.In a world without backtraces for errors, it'd also allow a hint to the compiler that it should point the finger at the code that caused the instantiation.Well, obviously we want backtraces for instantiation errors. But that's as well, not instead of! :-)
Dec 13 2007
Janice Caron wrote:On 12/13/07, Jason House <jason.james.house gmail.com> wrote:I don't understand how it's not an error if you can't instantiate the template.Janice Caron Wrote:You're missing the point, which is IT'S NOT AN ERROR. It's a substitution failure - and substitution failure IS NOT AN ERROR. That's a basic principle of template programming.On 12/13/07, Aziz K. <aziz.kerim gmail.com> wrote:I'd prefer a static assert. As with all errors, I'd want a backtrace.Why not use a static assert: static assert(0, "Substitution Failure");A static assert is a compile error. Different thing. What you want is for the template not to be instanted, not for it to be instantiated with a compile error. Put it another way. Suppose you write S(int) s; Which would you prefer - an error message saying that s couldn't be instantiated (giving the filename and line number of the above line), or an error message saying that a static assert in the middle of some library file had been hit?
Dec 13 2007
Ary Borenszweig wrote:Janice Caron wrote:Because it could potentially instantiate a different (overloaded) template. - Gregor RichardsOn 12/13/07, Jason House <jason.james.house gmail.com> wrote:I don't understand how it's not an error if you can't instantiate the template.Janice Caron Wrote:You're missing the point, which is IT'S NOT AN ERROR. It's a substitution failure - and substitution failure IS NOT AN ERROR. That's a basic principle of template programming.On 12/13/07, Aziz K. <aziz.kerim gmail.com> wrote:I'd prefer a static assert. As with all errors, I'd want a backtrace.Why not use a static assert: static assert(0, "Substitution Failure");A static assert is a compile error. Different thing. What you want is for the template not to be instanted, not for it to be instantiated with a compile error. Put it another way. Suppose you write S(int) s; Which would you prefer - an error message saying that s couldn't be instantiated (giving the filename and line number of the above line), or an error message saying that a static assert in the middle of some library file had been hit?
Dec 13 2007
"Ary Borenszweig" <ary esperanto.org.ar> kirjoitti viestissä news:fjrqqp$1f0e$1 digitalmars.com...Janice Caron wrote:It should *not* be an error of the template that a certain call can't instantiate it, since another (overloaded) template, as Gregor mentioned, can possibly be instantiated. That's basically what the current template with static if forces us to do: make it an error in the template, if we want to avoid template bloat. Instead, the error should be at the site of instatiation, if no template matches. When the template instatiation fails because we've found a matching template where specific overloaded specializations are combined into the single template, and where a specific condition doesn't exist for the template to be useful - eg. if it fails the isFloatingPoint!(T) and passesSomeVeryComplicatedTest!(T) example conditions from Janice's first post in this thread, then 1) with a static assert and no specializations we get an error, inside the code of the template; 2) with Janice's syntax, the compiler would note that this template didn't match, and proceed onward with the testing of other templates, finally giving an error at the location of instantiation.On 12/13/07, Jason House <jason.james.house gmail.com> wrote:I don't understand how it's not an error if you can't instantiate the template.Janice Caron Wrote:You're missing the point, which is IT'S NOT AN ERROR. It's a substitution failure - and substitution failure IS NOT AN ERROR. That's a basic principle of template programming.On 12/13/07, Aziz K. <aziz.kerim gmail.com> wrote:I'd prefer a static assert. As with all errors, I'd want a backtrace.Why not use a static assert: static assert(0, "Substitution Failure");A static assert is a compile error. Different thing. What you want is for the template not to be instanted, not for it to be instantiated with a compile error. Put it another way. Suppose you write S(int) s; Which would you prefer - an error message saying that s couldn't be instantiated (giving the filename and line number of the above line), or an error message saying that a static assert in the middle of some library file had been hit?
Dec 13 2007
Janice Caron Wrote:You're missing the point, which is IT'S NOT AN ERROR. It's a substitution failure - and substitution failure IS NOT AN ERROR. That's a basic principle of template programming.That's certainly true in C++, but I was not aware that was the way D template programming was intended to work. Static if seems like a much cleaner way to do things. If it is intended to have more than one templated definition that could match, I'd prefer to see D try to instantiate all candidates, and ensure that all but one instance has an error. If more than one matches successfully, the code wasn't coded well enough. If all throw an error, then the respective errors for each are printed and allows the user to see what's going wrong with each candidate.
Dec 13 2007
On 12/13/07, Jason House <jason.james.house gmail.com> wrote:If more than one matches successfully, the code wasn't coded well enough.But then you'd have to do template A(T:int) {/*code*/} template A(T:anything except an int){/*code*/} Even apart from the fact that there's no way to express that, it seems silly. It's perfectly reasonable to allow multiple matches. The compiler simply tries the most specialised first.
Dec 13 2007
Janice Caron wrote:On 12/13/07, Jason House <jason.james.house gmail.com> wrote:You can do the following for something so simple template A(T){ static if (T:int){/*code*/} else {/*code*/} } I've always been under the impression that use of static if is the "D way". Maybe that assumption is wrong. If my assumption isn't wrong, then attempts at one or more substitutions will be a rare exception rather than the rule. For rarer uses of code, if there's a chance the programmer (or more likely, a later code maintainer) can get confused, then I think it's better to err on the side of rigorous compile-time errors.If more than one matches successfully, the code wasn't coded well enough.But then you'd have to do template A(T:int) {/*code*/} template A(T:anything except an int){/*code*/}
Dec 13 2007
On 12/14/07, Jason House <jason.james.house gmail.com> wrote:I've always been under the impression that use of static if is the "D way".It's a choice. It happens to be my /preferred/ choice, but the multiple-templates way still needs to be supported.if there's a chance the programmer (or more likely, a later code maintainer) can get confused, then I think it's better to err on the side of rigorous compile-time errors.None of which changes the fact that, as I keep stressing, IT'S NOT AN ERROR to fail to match. One should not be forced to generate an error, when there plainly isn't one. Even if you /only/ use the static if style, and there are no alternative overloads, at the end of your chain of static ifs, you still want to be able so say static template(fail) (or whatever syntax is deemed right), rather than static assert, because if the template can't be instantiated at all, yes there's an error /somewhere/ -- but it's not in the template code; it's in the calling code - and that's the only place an error should be reported.
Dec 13 2007
Janice Caron Wrote:On 12/14/07, Jason House <jason.james.house gmail.com> wrote:After reflecting, I agree. What I'd been talking about assumes a mostly orthogonal split of template parameters rather than a hierarchy of approximate matches. Here's something more along the lines of what I was thinking about: template(T,U) { void foo(); } template(T : int,U){ void foo(); } template(T,U : int){ void foo(); } foo!(int,int)(); If both the 2nd and 3rd template works, which should the compiler choose? Maybe The 2nd template should assert U can't be int and the 3rd template should assert T can't be int. Even if that's done, is it an error or should the default be used? It very well could be the programmer never intended both parameters to be integers. Using the generic default may be a logic error. In this type of situation, I think it may help to force the programmer to be more explicit... such that if they don't catch this case properly, instantiating with both ints should be a compile-time error.I've always been under the impression that use of static if is the "D way".It's a choice. It happens to be my /preferred/ choice, but the multiple-templates way still needs to be supported.Even if you /only/ use the static if style, and there are no alternative overloads, at the end of your chain of static ifs, you still want to be able so say static template(fail) (or whatever syntax is deemed right), rather than static assert, because if the template can't be instantiated at all, yes there's an error /somewhere/ -- but it's not in the template code; it's in the calling code - and that's the only place an error should be reported.I have to disagree here. That's like saying it's incorrect to use an assert in an "in" contract. The same logic could apply. The caller passed in incorrect data, so the error occurred in the caller, not the callee. I just can't buy that. The callee can provide context-specific errors (free text detailing the likely problem or the logical condition that failed). I don't view template instantiation any differently. If there's an error, I want to templated code's perspective of what the error is *and* a complete backtrace. Now, when I say "an error", I mean a real error... It may be true that SFINAE when alternatives exist, but when you exhaust alternatives, it's an error.
Dec 14 2007
Reply to Jason,Janice Caron wrote:the problem with static if is that it turns into a work-or-die-hard solution. Once the static if is gotten to, there is no way to back out and say "I don't known how to handle this". The template(fail) would allow for complex static logic inside a template that can then be counted as a "this doesn't match, try other things" cases. This would come in handy in cases where you are are making a special cases handler template but want to be able to also have other templates be tried. Example (each case maintained independently) template Foo(T) { static if(/*logic 1 on T*/) /* code */ else template(fail); } template Foo(T) { static if(/*logic 2 on T*/) /* code */ else template(fail); } template Foo(T) { /* general case code */ }On 12/13/07, Jason House <jason.james.house gmail.com> wrote:You can do the following for something so simple template A(T){ static if (T:int){/*code*/} else {/*code*/} }If more than one matches successfully, the code wasn't coded well enough.But then you'd have to do template A(T:int) {/*code*/} template A(T:anything except an int){/*code*/}
Dec 14 2007
On 12/14/07, BCS <ao pathlink.com> wrote:Example (each case maintained independently)I don't know if this is reasonable, because you've got multiple different versions of Foo(T). But maybe...template Foo(T) { static if(/*logic 1 on T*/) /* code */ else template(fail); } template Foo(T) { static if(/*logic 2 on T*/) /* code */ else template(fail); } template Foo(T) { /* general case code */ }My feeling is, you could recode that as template Foo(T) { static if(/*logic 1 on T*/) /* code */ else static if(/*logic 2 on T*/) /* code */ else /* general case code */ } without needing either specialisation or template(fail). (But there are other cases where it /would/ be useful, obviously).
Dec 14 2007
Reply to Janice,On 12/14/07, BCS <ao pathlink.com> wrote:That only works if the maintainers of the two templates work together. Here is an example where they wouldn't be: ////// module A; void Func(T)(T t); // does some stuff with a T, Expects to find a Go(T) that works for T ////// module B; import A; void Go(T: B.Type)(T t); // library that works with B.Type and interacts with A.Func ////// module C; import A; void Go(T: C.Thing)(T t); // different library that works with C.Thing and interacts with A.Func ////// module D; import A; import B; import C; // use it all here Now that works as is (assuming no errors in my typing) but if you now want to have a module that defines a Go(T) that uses static if's to find if the T is something it can handle, you can only have one of those.Example (each case maintained independently)I don't know if this is reasonable, because you've got multiple different versions of Foo(T). But maybe...template Foo(T) { static if(/*logic 1 on T*/) /* code */ else template(fail); } template Foo(T) { static if(/*logic 2 on T*/) /* code */ else template(fail); } template Foo(T) { /* general case code */ }My feeling is, you could recode that as template Foo(T) { static if(/*logic 1 on T*/) /* code */ else static if(/*logic 2 on T*/) /* code */ else /* general case code */ } without needing either specialisation or template(fail). (But there are other cases where it /would/ be useful, obviously).
Dec 14 2007
On 12/14/07, BCS <ao pathlink.com> wrote:That only works if the maintainers of the two templates work together. Here is an example where they wouldn't be:Gotcha. Well, it seems doable, so long as there is zero chance of order-dependency creeping it. That would be my only worry. If order dependency does turn out to be an issue, then it might be wise to consider the alternative (and I believe, equivalent) suggestion: template A(T:if(someTest!(T))) { /*code*/ } which would eliminate the need for that sort of overloading, but still give just as much power to template programming.
Dec 14 2007
Reply to Janice,On 12/14/07, BCS <ao pathlink.com> wrote:I think that would be preferable in some ways because it would place the logic in a consistent place. OTOH it forces the logic into a "single expression" form. I guess you can always push the login into another template. In the end it's the functionality I want, as long as the syntax is usable it's all the same to me.That only works if the maintainers of the two templates work together. Here is an example where they wouldn't be:Gotcha. Well, it seems doable, so long as there is zero chance of order-dependency creeping it. That would be my only worry. If order dependency does turn out to be an issue, then it might be wise to consider the alternative (and I believe, equivalent) suggestion: template A(T:if(someTest!(T))) { /*code*/ } which would eliminate the need for that sort of overloading, but still give just as much power to template programming.
Dec 14 2007
BCS wrote:That only works if the maintainers of the two templates work together. Here is an example where they wouldn't be: ////// module A; void Func(T)(T t); // does some stuff with a T, Expects to find a Go(T) that works for T ////// module B; import A; void Go(T: B.Type)(T t); // library that works with B.Type and interacts with A.Func ////// module C; import A; void Go(T: C.Thing)(T t); // different library that works with C.Thing and interacts with A.Func ////// module D; import A; import B; import C; // use it all here Now that works as is (assuming no errors in my typing) but if you now want to have a module that defines a Go(T) that uses static if's to find if the T is something it can handle, you can only have one of those.Static import for the win! You might need some glue to hold it all together, and you'd have to define it at the location of use: template Go(T) { static if (I can handle it) { struct Go {} } else static if (compiles, A.Go!(T)) { alias A.Go!(T) Go; } else ... } Okay, that's ugly, and it puts the burden closer to the user. But it works, and it's not a terribly common situation.
Dec 14 2007
Reply to Christopher,BCS wrote:Garsh Darn It!!! while that doesn't even get close to doing what I wanted (I think) it does bring up the point that what I was proposing doesn't even work because the template function in A doesn't import anything with regards to B and C. The only way to make it work would be to mixin stuff from A into D and that just gets a bit nasty. <grumble/> OTOH it brings up an interesting question, what syntactic scope does a template get instanced in. The scope it's defined in, the scope it's used in or the scope the thing it's specialized on is defined in. Or is it come combination of the three? module A; struct B {} struct C { B b; } void Do(T)(T t){writef("hello world\n");} module B void Do(T)(T t){Do(t.b);} module C; import A; import B; C c; Do(c); what happens? B.Do can see into A b/c it can see A.C.b so can it see A.Do as well?That only works if the maintainers of the two templates work together. Here is an example where they wouldn't be: ////// module A; void Func(T)(T t); // does some stuff with a T, Expects to find a Go(T) that works for T ////// module B; import A; void Go(T: B.Type)(T t); // library that works with B.Type and interacts with A.Func ////// module C; import A; void Go(T: C.Thing)(T t); // different library that works with C.Thing and interacts with A.Func ////// module D; import A; import B; import C; // use it all here Now that works as is (assuming no errors in my typing) but if you now want to have a module that defines a Go(T) that uses static if's to find if the T is something it can handle, you can only have one of those.Static import for the win! You might need some glue to hold it all together, and you'd have to define it at the location of use: template Go(T) { static if (I can handle it) { struct Go {} } else static if (compiles, A.Go!(T)) { alias A.Go!(T) Go; } else ... } Okay, that's ugly, and it puts the burden closer to the user. But it works, and it's not a terribly common situation.
Dec 14 2007
Reply to Janice,I would like to propose a new statement: static template(fail); which causes a compile-time substitution failure. And remember: SFINAE - Substitution Failure Is Not An Error Let me give you an example: struct S(T) { static if(isFloatingPoint!(T)) { /*...*/ } else static if(passesSomeVeryComplicatedTest!(T)) { /*...*/ } else { static template(fail); // SFINAE } } This has advantages over old-style specialisation.vote++ either for the "static template(fail)" or "T:if(exp)" form
Dec 13 2007
BCS wrote:Reply to Janice,static template(fail) seems a bit more general purpose so probably better, but the syntax makes me go "uhhh, what?" I think a different syntax would be good, but the idea is sound. - Gregor RichardsI would like to propose a new statement: static template(fail); which causes a compile-time substitution failure. And remember: SFINAE - Substitution Failure Is Not An Error Let me give you an example: struct S(T) { static if(isFloatingPoint!(T)) { /*...*/ } else static if(passesSomeVeryComplicatedTest!(T)) { /*...*/ } else { static template(fail); // SFINAE } } This has advantages over old-style specialisation.vote++ either for the "static template(fail)" or "T:if(exp)" form
Dec 13 2007
On 12/13/07, Gregor Richards <Richards codu.org> wrote:I think a different syntax would be good, but the idea is sound.Hey, we always argue about the syntax. It's a tradition! :-) Yeah, I don't care about the syntax. I though of "static break" first, but then I thought that might conflict with possible future features (static switch/case/break anyone?). "template(fail)" was the best I could come up with quickly, but probably not the best we can do between us.
Dec 13 2007
Janice Caron, el 13 de diciembre a las 19:47 me escribiste:On 12/13/07, Gregor Richards <Richards codu.org> wrote:template break? =) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- "Lidiar" no es lo mismo que "holguear"; ya que "lidiar" es relativo a "lidia" y "holguear" es relativo a "olga". -- Ricardo VaporesoI think a different syntax would be good, but the idea is sound.Hey, we always argue about the syntax. It's a tradition! :-) Yeah, I don't care about the syntax. I though of "static break" first, but then I thought that might conflict with possible future features (static switch/case/break anyone?). "template(fail)" was the best I could come up with quickly, but probably not the best we can do between us.
Dec 13 2007
Yes, idea is good, but proposed syntax is bad.
Dec 13 2007
Janice Caron wrote:I would like to propose a new statement: static template(fail); which causes a compile-time substitution failure. And remember: SFINAE - Substitution Failure Is Not An Error Let me give you an example: struct S(T) { static if(isFloatingPoint!(T)) { /*...*/ } else static if(passesSomeVeryComplicatedTest!(T)) { /*...*/ } else { static template(fail); // SFINAE } } This has advantages over old-style specialisation.All you need is *anything* that would generate an ordinary compiler error. So actually your suggested syntax may /already/ work! --bb
Dec 13 2007
On 12/13/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:All you need is *anything* that would generate an ordinary compiler error.The idea is /not/ to generate a compiler error. :-)
Dec 13 2007
Janice Caron wrote:On 12/13/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:Right, and it won't because as you've been reiterating "substitution error is not a failure". If the template results in a something that's an ordinary syntax error then it's just a substitution failure. "static assert" is special in that it short circuits that behavior. --bbAll you need is *anything* that would generate an ordinary compiler error.The idea is /not/ to generate a compiler error. :-)
Dec 13 2007
On 12/13/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:If the template results in a something that's an ordinary syntax error then it's just a substitution failure. "static assert" is special in that it short circuits that behavior.Really? Wow! I'm going to have to try that now!
Dec 13 2007
On Thu, 13 Dec 2007 20:53:23 -0000, Janice Caron <caron800 googlemail.com> wrote:On 12/13/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:So did it work? I guess you are using the Unix silence is golden principle.If the template results in a something that's an ordinary syntax error then it's just a substitution failure. "static assert" is special in that it short circuits that behavior.Really? Wow! I'm going to have to try that now!
Dec 13 2007
Bruce Adams wrote:On Thu, 13 Dec 2007 20:53:23 -0000, Janice Caron <caron800 googlemail.com> wrote:I've tried it and it didn't work for me.On 12/13/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:So did it work? I guess you are using the Unix silence is golden principle.If the template results in a something that's an ordinary syntax error then it's just a substitution failure. "static assert" is special in that it short circuits that behavior.Really? Wow! I'm going to have to try that now!
Dec 13 2007
On 12/14/07, Robert DaSilva <sp.unit.262+digitalmars gmail.com> wrote:I've tried it and it didn't work for me.I didn't think it would. I didn't get a chance to try before Robert, because of timezone differences (I was in bed asleep between the two posts). Still, it's nice to see that folk in other parts of the globe can do the experiment while I'm tucked up in bed! :-) I believe that under the current system, if the (T:whatever) rule passes, the template is deemed to have matched, and nothing can subsequently change its mind. Any compile error encountered from there on is considered a real compile error. And I think that's correct behavior. The "template(fail)" suggestion would add a way to say, after the event, "I've changed my mind. Please consider this unmatched after all".
Dec 13 2007
On Fri, 14 Dec 2007 07:33:18 -0000, Janice Caron <caron800 googlemail.com> wrote:On 12/14/07, Robert DaSilva <sp.unit.262+digitalmars gmail.com> wrote:You've just added our old friend the backtracking algorithm. It does seem to me that as templates develop further they become more and more like a compile time prolog interpreter. This is how prolog predicates work. Each one is matched in turn and everything is undone unless it returns true.I've tried it and it didn't work for me.I didn't think it would. I didn't get a chance to try before Robert, because of timezone differences (I was in bed asleep between the two posts). Still, it's nice to see that folk in other parts of the globe can do the experiment while I'm tucked up in bed! :-) I believe that under the current system, if the (T:whatever) rule passes, the template is deemed to have matched, and nothing can subsequently change its mind. Any compile error encountered from there on is considered a real compile error. And I think that's correct behavior. The "template(fail)" suggestion would add a way to say, after the event, "I've changed my mind. Please consider this unmatched after all".
Dec 14 2007
Janice Caron Wrote:I believe that under the current system, if the (T:whatever) rule passes, the template is deemed to have matched, and nothing can subsequently change its mind. Any compile error encountered from there on is considered a real compile error. And I think that's correct behavior. The "template(fail)" suggestion would add a way to say, after the event, "I've changed my mind. Please consider this unmatched after all".IMHO, this should have been part of the original post. Your suggestion now sounds much better to me. Of course, I don't like the proposed syntax.
Dec 14 2007
what would this do?: template Foo(T) { static if(logic1!(T)) template(fail); } template Foo(T) { static if(logic2!(T)) template(fail); } from a programers level, it might be valid. My though is (an wow could this be costly) try all cases*, if there isn't exactly one match, error. * Walter's not going to like that for performance reasons.
Dec 14 2007
On Fri, 14 Dec 2007 19:09:25 -0000, BCS <ao pathlink.com> wrote:what would this do?: template Foo(T) { static if(logic1!(T)) template(fail); } template Foo(T) { static if(logic2!(T)) template(fail); } from a programers level, it might be valid. My though is (an wow could this be costly) try all cases*, if there isn't exactly one match, error. * Walter's not going to like that for performance reasons.I'm not so sure about that. Its a bit like saying he wouldn't like you to write poorly designed / optimised code. He may not like it but a programming language can't help but permit it even if it does discourage it.
Dec 14 2007
Reply to Bruce,On Fri, 14 Dec 2007 19:09:25 -0000, BCS <ao pathlink.com> wrote:I'm taking about DMD's performance. The compile time cost of find a template match could go through the roof with the "backtracking finds one match" solution.what would this do?: template Foo(T) { static if(logic1!(T)) template(fail); } template Foo(T) { static if(logic2!(T)) template(fail); } from a programers level, it might be valid. My though is (an wow could this be costly) try all cases*, if there isn't exactly one match, error. * Walter's not going to like that for performance reasons.I'm not so sure about that. Its a bit like saying he wouldn't like you to write poorly designed / optimised code. He may not like it but a programming language can't help but permit it even if it does discourage it.
Dec 14 2007
On Fri, 14 Dec 2007 20:01:17 -0000, BCS <ao pathlink.com> wrote:Reply to Bruce,Prolog is entirely based on backtracking huge numbers of predicates and it doesn't run that slowly. I don't think it would be much of a problem in D unless you write a huge number of really complex evil templates and stick them all in one module. I'm not sure even the legendary obfuscator Downs could stretch it to breaking point. Mr. Blade library might come closer. Anyway, as with any language feature you should only pay for it if you use it. Unless you are overusing it, it shouldn't be a problem.On Fri, 14 Dec 2007 19:09:25 -0000, BCS <ao pathlink.com> wrote:I'm taking about DMD's performance. The compile time cost of find a template match could go through the roof with the "backtracking finds one match" solution.what would this do?: template Foo(T) { static if(logic1!(T)) template(fail); } template Foo(T) { static if(logic2!(T)) template(fail); } from a programers level, it might be valid. My though is (an wow could this be costly) try all cases*, if there isn't exactly one match, error. * Walter's not going to like that for performance reasons.I'm not so sure about that. Its a bit like saying he wouldn't like you to write poorly designed / optimised code. He may not like it but a programming language can't help but permit it even if it does discourage it.
Dec 14 2007
Reply to Bruce,On Fri, 14 Dec 2007 20:01:17 -0000, BCS <ao pathlink.com> wrote:take a look at scrapple.backmath, the bulk of it is a huge list of static ifs inside templates. The way it's set up now it doesn't do any backtracking, but I rather dislike the brut force approach it is taking ("is this xyzzy? No? how about xyzzY? No? How about...[next 100 lines skipped]") The way code seems to go, new stuff will get layered on top of old stuff. Add backtracking into the mix as part of the language and soon D will get a rep of "yah it's good, but I can wright, debug, compile and be done faster in C than I can compile in D".Reply to Bruce,Prolog is entirely based on backtracking huge numbers of predicates and it doesn't run that slowly. I don't think it would be much of a problem in D unless you write a huge number of really complex evil templates and stick them all in one module. I'm not sure even the legendary obfuscator Downs could stretch it to breaking point. Mr. Blade library might come closer. Anyway, as with any language feature you should only pay for it if you use it. Unless you are overusing it, it shouldn't be a problem.On Fri, 14 Dec 2007 19:09:25 -0000, BCS <ao pathlink.com> wrote:I'm taking about DMD's performance. The compile time cost of find a template match could go through the roof with the "backtracking finds one match" solution.what would this do?: template Foo(T) { static if(logic1!(T)) template(fail); } template Foo(T) { static if(logic2!(T)) template(fail); } from a programers level, it might be valid. My though is (an wow could this be costly) try all cases*, if there isn't exactly one match, error. * Walter's not going to like that for performance reasons.I'm not so sure about that. Its a bit like saying he wouldn't like you to write poorly designed / optimised code. He may not like it but a programming language can't help but permit it even if it does discourage it.
Dec 17 2007
On Mon, 17 Dec 2007 18:53:49 -0000, BCS <ao pathlink.com> wrote:Reply to Bruce,On Fri, 14 Dec 2007 20:01:17 -0000, BCS <ao pathlink.com> wrote:That is only the case if it is a programming style that is encouraged or frequently required. If it is for something that occurs rarely and is discouraged only bad programs will be tangled and bad programs will always be tangled. Is it really likely to occur often? and is there a better solution or workaround?take a look at scrapple.backmath, the bulk of it is a huge list of static ifs inside templates. The way it's set up now it doesn't do any backtracking, but I rather dislike the brut force approach it is taking ("is this xyzzy? No? how about xyzzY? No? How about...[next 100 lines skipped]") The way code seems to go, new stuff will get layered on top of old stuff. Add backtracking into the mix as part of the language and soon D will get a rep of "yah it's good, but I can wright, debug, compile and be done faster in C than I can compile in D".Prolog is entirely based on backtracking huge numbers of predicates and it doesn't run that slowly. I don't think it would be much of a problem in D unless you write a huge number of really complex evil templates and stick them all in one module. I'm not sure even the legendary obfuscator Downs could stretch it to breaking point. Mr. Blade library might come closer. Anyway, as with any language feature you should only pay for it if you use it. Unless you are overusing it, it shouldn't be a problem.
Dec 17 2007
Reply to Bruce,That is only the case if it is a programming style that is encouraged or frequently required. If it is for something that occurs rarely and is discouraged only bad programs will be tangled and bad programs will always be tangled. Is it really likely to occur often?and is there a better solution or workaround?take that last bit out of context and you have just stated my concern. Before template(fail) is added it's implications and alternatives should be considered. Is there some way to make it would neatly and consistently without adding a huge cost? I'm just stating concerns, not saying it's a bad idea.
Dec 18 2007
Robert DaSilva wrote:Bruce Adams wrote:Why be so cryptic? Show us what you tried for goodness sake. --bbOn Thu, 13 Dec 2007 20:53:23 -0000, Janice Caron <caron800 googlemail.com> wrote:I've tried it and it didn't work for me.On 12/13/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:So did it work? I guess you are using the Unix silence is golden principle.If the template results in a something that's an ordinary syntax error then it's just a substitution failure. "static assert" is special in that it short circuits that behavior.Really? Wow! I'm going to have to try that now!
Dec 14 2007
Bill Baxter wrote:Robert DaSilva wrote:Ok so I tried it myself. Apparently neither D nor C++ works the way I thought it did w.r.t SFINAE. It seems that SFINAE only applies to things in the function's declaration, not its contents. I suppose that does make sense, because otherwise it would be damned hard to figure out when you have a syntax error in specialized templates. Lutz Kettner has a pretty good explanation of how it works: http://www.mpi-inf.mpg.de/~kettner/courses/lib_design_03/notes/meta.html (Wikipedia's explanation is pathetic.) My appologies. Here are my tests: =========C++========= #include <stdio.h> template <typename T> struct Foo { T x; void spew() { printf("Generic struct"); } }; template <typename T> struct Foo<T*> { T x; void spew() { printf("Partial specialized struct\n"); // T y = x.foo; // an error } }; template <typename T> void func(T x) { printf("generic func\n"); } template <> void func<int*>(int* x) { printf("total specialized func\n"); //int z = x.foo; // an error } int main() { int *x; func<int*>(x); Foo<int*> ptrFoo; ptrFoo.spew(); return 0; } ============D================ module sfinae; import std.stdio; void func(T)(T x) { writefln("generic version"); } void func(T:T[])(T[] x) { writefln("specialized version"); // writefln(T.foo); // an error } void main() { int[] x; func!(int[])(x); } =============================== --bbBruce Adams wrote:Why be so cryptic? Show us what you tried for goodness sake. --bbOn Thu, 13 Dec 2007 20:53:23 -0000, Janice Caron <caron800 googlemail.com> wrote:I've tried it and it didn't work for me.On 12/13/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:So did it work? I guess you are using the Unix silence is golden principle.If the template results in a something that's an ordinary syntax error then it's just a substitution failure. "static assert" is special in that it short circuits that behavior.Really? Wow! I'm going to have to try that now!
Dec 14 2007
Reply to Bill,Ok so I tried it myself. Apparently neither D nor C++ works the way I thought it did w.r.t SFINAE. It seems that SFINAE only applies to things in the function's declaration, not its contents. I suppose that does make sense, because otherwise it would be damned hard to figure out when you have a syntax error in specialized templates.The body of a template must be syntactically correct no matter what. If template(fail) gets in I would want semantic errors during specialization to be errors. I would expect the programer to catch and bail when unusable arguments are given.
Dec 14 2007
Janice Caron wrote:I would like to propose a new statement: static template(fail); which causes a compile-time substitution failure. And remember: SFINAE - Substitution Failure Is Not An Error Let me give you an example: struct S(T) { static if(isFloatingPoint!(T)) { /*...*/ } else static if(passesSomeVeryComplicatedTest!(T)) { /*...*/ } else { static template(fail); // SFINAE } } This has advantages over old-style specialisation.I guess this would require the compiler to not complain if I did this? struct S(T) { static if(is(T==int)) static template(fail); } struct S(T) { } S!(int); Sean
Dec 13 2007
Sean Kelly wrote:Janice Caron wrote:No, you have to make one of them specialized somehow, otherwise it's just a good old fashioned redundant definition error. Like if you tried to make two functions "void foo(int)". --bbI would like to propose a new statement: static template(fail); which causes a compile-time substitution failure. And remember: SFINAE - Substitution Failure Is Not An Error Let me give you an example: struct S(T) { static if(isFloatingPoint!(T)) { /*...*/ } else static if(passesSomeVeryComplicatedTest!(T)) { /*...*/ } else { static template(fail); // SFINAE } } This has advantages over old-style specialisation.I guess this would require the compiler to not complain if I did this? struct S(T) { static if(is(T==int)) static template(fail); } struct S(T) { } S!(int); Sean
Dec 13 2007
Bill Baxter wrote:Sean Kelly wrote:So either way I'd need to use specialization? I suppose this would still simplify coding a tad, but... SeanJanice Caron wrote:No, you have to make one of them specialized somehow, otherwise it's just a good old fashioned redundant definition error. Like if you tried to make two functions "void foo(int)".I would like to propose a new statement: static template(fail); which causes a compile-time substitution failure. And remember: SFINAE - Substitution Failure Is Not An Error Let me give you an example: struct S(T) { static if(isFloatingPoint!(T)) { /*...*/ } else static if(passesSomeVeryComplicatedTest!(T)) { /*...*/ } else { static template(fail); // SFINAE } } This has advantages over old-style specialisation.I guess this would require the compiler to not complain if I did this? struct S(T) { static if(is(T==int)) static template(fail); } struct S(T) { } S!(int);
Dec 13 2007
On 12/13/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:No, you have to make one of them specialized somehow, otherwise it's just a good old fashioned redundant definition error. Like if you tried to make two functions "void foo(int)".I agree. But in the particular example you cited, you could instead just write struct S(T) { static if(is(T==int)) static template(fail); } because the "else" condition is empty. Then S!(int) would fail, but S!(float) would succeed.
Dec 13 2007
I thought about this issue a little bit before I went to sleep yesterday. It just occurred to me that a pragma statement would be perfect to solve this problem. Especially since it wouldn't require any modifications to a D parser. struct S(T) { static if(isFloatingPoint!(T)) { /*...*/ } /* other tests */ else pragma(fail_instantiation); } With this statement we can give a hint to the compiler to abort instantiation and try other (specialized) templates. The question now is which identifier would be a good, descriptive and concise one. .) fail_instantiation // good one, but too long? .) fail_i11n // shortened similar to i18n/internationalization .) fail // sounds too general and may conflict with possible future uses. .) substitution_failure // a bit too long? .) instantiation_failure // ditto .) iFail // *rolls eyes* .) stop_it_plz_1exclamation_mark11 // :D Well, I guess some of you may have more, better suggestions. Let's see what the community votes for.
Dec 14 2007