www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: "SFINAE is Evil"

reply Jason House <jason.james.house gmail.com> writes:
I should probably expand this question...

Who uses templates in D? What is the most complex use you've done? Do you ever
plan to get more complex? Would SFINAE make your life easier or harder?

I've written templates classes that have one definition, and used static if as
needed for specialization. I don't forsee more complex usage and view SFINAE as
something that would mask bugs.



Jason House Wrote:

 SFINAE - Substitution failure is not an error
 
 This post is all about templates and their static if counterparts.  With the
 enhanced expressiveness of D, is there a need for SFINAE from C++? 
 Essentially, when a specialization exists, if the compilation of the
 specialization fails, the compiler silently gives up on it and goes to the
 next more general case.  In my mind, this is both dangerous and a loop hole
 for long compile times (as the compiler instantiates extra template
 instances).
 
 What I want to know is this:  Who uses SFINAE in D, and why?  Is this a
 matter of convenience or a requirement.  If required, I assume it's from a
 lack of expressiveness in defining a template's conditions.  Could this be
 overcome with use of static if's instead?
 
 PS: Post title is a quote of Russell Lewis from another thread.

Mar 21 2008
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Jason House wrote:
 I should probably expand this question...
 
 Who uses templates in D? What is the most complex use you've done? Do you ever
plan to get more complex? Would SFINAE make your life easier or harder?
 
 I've written templates classes that have one definition, and used static if as
needed for specialization. I don't forsee more complex usage and view SFINAE as
something that would mask bugs.

I don't have time to write more right now, but Lutz Kettner gives a pretty good examples of using SFINAE here: http://www.mpi-inf.mpg.de/~kettner/courses/lib_design_03/notes/meta.html#Constraining http://www.mpi-inf.mpg.de/~kettner/courses/lib_design_03/notes/meta.html#Classification Certainly the Enable_if template can be replaced by a simple static if. Maybe the other one too. The main problem I have with templates in D is that traits templates are severely limited by the inability to define specializations for a template in different modules. Like the IsVector_2 template Lutz talks about. If all specializations have to be in one file, then the library designer has to know in advance all the types that can ever be used as a Vector2 and clearly that limits the utility of it. Maybe this is coming in D2. I think I did a test recently and it still didn't work. --bb
Mar 22 2008
next sibling parent reply Jason House <jason.james.house gmail.com> writes:
I look forward to when you can write more... Are you trying to say SFINAE is
needed? I look at the examples and still think probably not. The traits example
can be solved cleanly in D, just like enable if. The toughest one is the vector
2 example. I think detection of what is a vector 2 could be done with an
interface? The rest of the examples I reaf are SFINAE free.


Bill Baxter Wrote:

 Jason House wrote:
 I should probably expand this question...
 
 Who uses templates in D? What is the most complex use you've done? Do you ever
plan to get more complex? Would SFINAE make your life easier or harder?
 
 I've written templates classes that have one definition, and used static if as
needed for specialization. I don't forsee more complex usage and view SFINAE as
something that would mask bugs.

I don't have time to write more right now, but Lutz Kettner gives a pretty good examples of using SFINAE here: http://www.mpi-inf.mpg.de/~kettner/courses/lib_design_03/notes/meta.html#Constraining http://www.mpi-inf.mpg.de/~kettner/courses/lib_design_03/notes/meta.html#Classification Certainly the Enable_if template can be replaced by a simple static if. Maybe the other one too. The main problem I have with templates in D is that traits templates are severely limited by the inability to define specializations for a template in different modules. Like the IsVector_2 template Lutz talks about. If all specializations have to be in one file, then the library designer has to know in advance all the types that can ever be used as a Vector2 and clearly that limits the utility of it. Maybe this is coming in D2. I think I did a test recently and it still didn't work. --bb

Mar 22 2008
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
I was looking around for something good on traits templates, the hows 
and whys.
This seems to be pretty decent:
http://www.cantrip.org/traits.html

--bb
Mar 22 2008
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
The description of traits in Boost is quite succinct and hits the good 
points -- particularly about the non-intrusive part:
http://www.boost.org/more/generic_programming.html#traits

I think most traits-like things can be done in D if you require that 
people modify their classes.  But the non-intrusiveness is one of key 
parts of what makes traits templates a good building block.

--bb
Mar 22 2008
parent Jason House <jason.james.house gmail.com> writes:
Bill Baxter Wrote:

 The description of traits in Boost is quite succinct and hits the good 
 points -- particularly about the non-intrusive part:
 http://www.boost.org/more/generic_programming.html#traits
 
 I think most traits-like things can be done in D if you require that 
 people modify their classes.  But the non-intrusiveness is one of key 
 parts of what makes traits templates a good building block.
 
 --bb

Mar 22 2008
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
 Bill Baxter Wrote:

 Jason House wrote:
 I should probably expand this question...

 Who uses templates in D? What is the most complex use you've done? 



or harder?
 I've written templates classes that have one definition, and used 



usage and view SFINAE as something that would mask bugs.
 I don't have time to write more right now, but
 Lutz Kettner gives a pretty good examples of using SFINAE here:
 


 


Jason House wrote:
 I look forward to when you can write more... Are you trying to say SFINAE is
needed? 

Yes, I'm saying I haven't yet found a case where I'm using it (but that doesn't mean there isn't one!) However, I did start a thread a while back about a way to introduce /controlled/ SFINAE. Or rather a way to explicitly say you want to try something, and if it does generate an error, try something else. Compile time try-catch. Look for the subject "static try catch construct would be helpful" in this newsgroup. I still think that would be useful.
 I look at the examples and still think probably not. 

Yes, with those examples I agree with you. They only use that Enable_if template which is easily replaced by a static if.
 The traits example can be solved cleanly in D, just like enable if. 

 The toughest one is the vector 2 example. I think detection of what 

I read are SFINAE free. Yes, well the vector2 one is the important one (but the parts that have to do with SFINAE aren't the problem). The traits templates can be thought of like compile-time adapters or facades. So they are like compile-time interfaces in a way. But they are non-intrusive. Fred provides library Foo. Barny provides type Bar. Wilma wants to use Barny's Bar with Fred's Foo, but Fred and Barney designed their code separately and the interfaces are compatible. So what traits templates do is give Fred's Foo a way to /ask Wilma/ what to do with Barney's Bar without having to get Barney involved. Wilma provides a FooTraits!(T:Bar) specialization, and Fred's Foo instantiates it and uses that to find out what it needs to know. Of course this presumes Fred designed Foo with this sort of flexibility in mind. Ok, so now that I've written all that out explicitly, I see that one nice but unessential thing about Traits as I've described them is that it operates in a "pull" manner. That is, when Wilma tries to create a Foo!(Bar), Foo just turns around and tries to instantiate a FooTraits!(Bar), which could come from anywhere (in C++ anyway), and in this case it comes from Wilma's code. So this can be worked around in D. It just requires switching to a "push" model. And that means the FooTraits must become an extra template parameter to Foo. So instead of Wilma just instantiating a Foo!(Bar) with the traits automatically ferreted out internally as FooTraits!(Bar), Wilma will need to explicitly pass the traits, like Foo!(Bar, WilmasFooTraitsForBar). So I guess it's not the end of the world. I can't think of any reason off the top of my head that using the push model would be a show stopper. It just isn't quite as slick. I guess it makes things difficult for function templates though. No IFTI if you have to provide a traits parameter explicitly. --bb
Mar 23 2008
parent reply Jason House <jason.james.house gmail.com> writes:
Bill Baxter wrote:
 Jason House wrote:
 I look forward to when you can write more... Are you trying to say SFINAE
 is needed?

Yes, I'm saying I haven't yet found a case where I'm using it (but that doesn't mean there isn't one!) However, I did start a thread a while back about a way to introduce /controlled/ SFINAE. Or rather a way to explicitly say you want to try something, and if it does generate an error, try something else. Compile time try-catch. Look for the subject "static try catch construct would be helpful" in this newsgroup. I still think that would be useful.

I also had the feeling of "SFINAE is needed, but I can't come up with any examples". I find it interesting that nobody posted a need for SFINAE. Because of that, and all the pitfalls, I agree that SFINAE as a default behavior is undesirable and should disapear from D. Rather than propose an alternative to it, I wanted to understand how it should be used in D. With no examples of it, I've started leaning toward simple removal of it. I started this thread thinking the likely outcome would be something like your proposal. Now I'm thinking that SFINAE is not needed. If that's not true, I'm thinking it may be better to enhance is clauses and/or CTFE to cover the (small) capability gap. What do you think of that? If you (and others paying attention to this thread) agree, how do we get the attention of Walter? Maybe it should be a feature request or an entry on the unofficial D wishlist?
Mar 24 2008
parent reply Georg Wrede <georg nospam.org> writes:
Jason House wrote:
 I also had the feeling of "SFINAE is needed, but I can't come up with any
 examples".  I find it interesting that nobody posted a need for SFINAE. 
 Because of that, and all the pitfalls, I agree that SFINAE as a default
 behavior is undesirable and should disapear from D.
 
 Rather than propose an alternative to it, I wanted to understand how it
 should be used in D.  With no examples of it, I've started leaning toward
 simple removal of it.  I started this thread thinking the likely outcome
 would be something like your proposal.  Now I'm thinking that SFINAE is not
 needed.  If that's not true, I'm thinking it may be better to enhance is
 clauses and/or CTFE to cover the (small) capability gap.
 
 What do you think of that?  If you (and others paying attention to this
 thread) agree, how do we get the attention of Walter?  Maybe it should be a
 feature request or an entry on the unofficial D wishlist?

I suspect it would be quite simple to add a compiler switch to turn SFINAE on or off? Since D2 is "experimental" anyway, we might have this switch for a few months, and then see if anybody actually used it. The default would be SF is an error.
Mar 25 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Georg Wrede wrote:
 Jason House wrote:
 I also had the feeling of "SFINAE is needed, but I can't come up with any
 examples".  I find it interesting that nobody posted a need for 
 SFINAE. Because of that, and all the pitfalls, I agree that SFINAE as 
 a default
 behavior is undesirable and should disapear from D.

 Rather than propose an alternative to it, I wanted to understand how it
 should be used in D.  With no examples of it, I've started leaning toward
 simple removal of it.  I started this thread thinking the likely outcome
 would be something like your proposal.  Now I'm thinking that SFINAE 
 is not
 needed.  If that's not true, I'm thinking it may be better to enhance is
 clauses and/or CTFE to cover the (small) capability gap.

 What do you think of that?  If you (and others paying attention to this
 thread) agree, how do we get the attention of Walter?  Maybe it should 
 be a
 feature request or an entry on the unofficial D wishlist?

I suspect it would be quite simple to add a compiler switch to turn SFINAE on or off? Since D2 is "experimental" anyway, we might have this switch for a few months, and then see if anybody actually used it. The default would be SF is an error.

That would be great. I'd love to try out such a switch. Though at the moment it would do me no good unless it were added to D1 also. Though rather than turning it off, I'd rather have a -v kind of switch that prints out a message whenever SFINAE is invoked, maybe with an instantiation stack trace. --bb
Mar 25 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
news:fsbp54$293h$1 digitalmars.com...

 That would be great.  I'd love to try out such a switch.  Though at the 
 moment it would do me no good unless it were added to D1 also.  Though 
 rather than turning it off, I'd rather have a -v kind of switch that 
 prints out a message whenever SFINAE is invoked, maybe with an 
 instantiation stack trace.

Great idea! <narrator>And with that, the suggestion began its slow, painful descent into the depths of the unread old posts of the NG, never to be seen again or commented on by the very man who could make a difference. Months later many would reminisce about what a good idea it was, and would sigh nostalgically over their youthful optimism.</narrator>
Mar 25 2008
next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Jarrett Billingsley wrote:

 "Bill Baxter" <dnewsgroup billbaxter.com> wrote in message
 <narrator>And with that, the suggestion began its slow, painful descent
 into the depths of the unread old posts of the NG, never to be seen again
 or
 commented on by the very man who could make a difference.  Months later
 many would reminisce about what a good idea it was, and would sigh
 nostalgically over their youthful optimism.</narrator>

That about sums it up :(
Mar 25 2008
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Jason House wrote:
 Jarrett Billingsley wrote:
 
 "Bill Baxter" <dnewsgroup billbaxter.com> wrote in message
 <narrator>And with that, the suggestion began its slow, painful descent
 into the depths of the unread old posts of the NG, never to be seen again
 or
 commented on by the very man who could make a difference.  Months later
 many would reminisce about what a good idea it was, and would sigh
 nostalgically over their youthful optimism.</narrator>

That about sums it up :(

Yes, sweet. Someone should post a self-referential url in this thread so it will be easier to find and refer to it later. :-) --bb
Mar 25 2008
prev sibling parent Jason House <jason.james.house gmail.com> writes:
Jarrett Billingsley wrote:

 "Bill Baxter" <dnewsgroup billbaxter.com> wrote in message
 news:fsbp54$293h$1 digitalmars.com...
 
 That would be great.  I'd love to try out such a switch.  Though at the
 moment it would do me no good unless it were added to D1 also.  Though
 rather than turning it off, I'd rather have a -v kind of switch that
 prints out a message whenever SFINAE is invoked, maybe with an
 instantiation stack trace.

Great idea! <narrator>And with that, the suggestion began its slow, painful descent into the depths of the unread old posts of the NG, never to be seen again or commented on by the very man who could make a difference. Months later many would reminisce about what a good idea it was, and would sigh nostalgically over their youthful optimism.</narrator>

I created an enhancement request (#1951) for this. That should (hopefully) gain visibility with Walter (and more importantly?) Andrei, who's been known to fully flex C++'s templates. Feel free to add individual ideas on what might be a good alternative to SFINAE. I really didn't put any in the enhancement request.
Mar 26 2008
prev sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bill Baxter wrote:
 
 I don't have time to write more right now, but
 Lutz Kettner gives a pretty good examples of using SFINAE here:
 http://www.mpi-inf.mpg.de/~kettner/courses/lib_design_03/notes/me
a.html#Constraining 
 
 http://www.mpi-inf.mpg.de/~kettner/courses/lib_design_03/notes/meta
html#Classification 
 
 

Upon reading that, it's amazing how much more simple(and powerful) meta-programming is in D. (having static if, is-expressions, aliases, and D template syntax) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Mar 26 2008
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Jason House wrote:
 I should probably expand this question...
 
 Who uses templates in D? What is the most complex use you've done? Do you ever
plan to get more complex? Would SFINAE make your life easier or harder?

Templates are utterly necessary and horribly untestable. I use them, but I try to keep them as braindead simple as possible. I've done a reasonable amount of work with simple templates, eg DUnit's assertions, and some slightly more complex stuff, as with DMocks, but nothing incredibly difficult. DMocks was mainly a matter of looping through reflection information and assembling some strings based on that, which wasn't so difficult; the hardest thing (besides debugging CTFE failures and oddities with mixins, but I did my best to limit the amount of both) was not being able to have a variable whose type was an empty tuple. I had to wrap the tuple in a templated class that would just not instantiate the arguments variable with an empty tuple. SFINAE isn't a problem for me -- I don't need to overload templates much. If I did, I'd do it like this: template Foo(T, U, V...) { static if (condition1) { alias FooSpecialization1!(T, U, V) Foo; } else // ... } The only thing the compiler could do to help me that it isn't doing is to make it an error to have overloaded templates.
 I've written templates classes that have one definition, and used static if as
needed for specialization. I don't forsee more complex usage and view SFINAE as
something that would mask bugs.

Same. The only issue is with templates from different modules or libraries. In this case, it could be helpful for the compiler to have an error message along the lines of: template instantiation Foo!(int, float, float, char[]): could not instantiate. Candidates are: valhalla.odin.Foo(T : long, U, T, V[char]) : char[] is not a V[char] valhalla.thor.Foo(T : class, U...) : int is not a class ...
Mar 22 2008
parent reply Jason House <jason.james.house gmail.com> writes:
Ok, so you're saying you could do without SFINAE?

Christopher Wright Wrote:

 Jason House wrote:
 I should probably expand this question...
 
 Who uses templates in D? What is the most complex use you've done? Do you ever
plan to get more complex? Would SFINAE make your life easier or harder?

Templates are utterly necessary and horribly untestable. I use them, but I try to keep them as braindead simple as possible. I've done a reasonable amount of work with simple templates, eg DUnit's assertions, and some slightly more complex stuff, as with DMocks, but nothing incredibly difficult. DMocks was mainly a matter of looping through reflection information and assembling some strings based on that, which wasn't so difficult; the hardest thing (besides debugging CTFE failures and oddities with mixins, but I did my best to limit the amount of both) was not being able to have a variable whose type was an empty tuple. I had to wrap the tuple in a templated class that would just not instantiate the arguments variable with an empty tuple. SFINAE isn't a problem for me -- I don't need to overload templates much. If I did, I'd do it like this: template Foo(T, U, V...) { static if (condition1) { alias FooSpecialization1!(T, U, V) Foo; } else // ... } The only thing the compiler could do to help me that it isn't doing is to make it an error to have overloaded templates.
 I've written templates classes that have one definition, and used static if as
needed for specialization. I don't forsee more complex usage and view SFINAE as
something that would mask bugs.

Same. The only issue is with templates from different modules or libraries. In this case, it could be helpful for the compiler to have an error message along the lines of: template instantiation Foo!(int, float, float, char[]): could not instantiate. Candidates are: valhalla.odin.Foo(T : long, U, T, V[char]) : char[] is not a V[char] valhalla.thor.Foo(T : class, U...) : int is not a class ...

Mar 22 2008
parent reply Christopher Wright <dhasenan gmail.com> writes:
Jason House wrote:
 Ok, so you're saying you could do without SFINAE?

Yes, and I wish I could do without templates.
Mar 22 2008
parent Georg Wrede <georg nospam.org> writes:
Christopher Wright wrote:
 Jason House wrote:
 
 Ok, so you're saying you could do without SFINAE?

Yes, and I wish I could do without templates.

I don't need templates. But that's probably because I only do apps. If I were to write libraries (even for myself), then I'd expect to be using templates in many, if not most of the functions. I's just that I currently don't run into things where I'd need a template. As for SFINAE, I can't even imagine where I'd gain with it.
Mar 25 2008