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.

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.

I get the feeling that a number of features in D can eventually be dumped in
favor of others. Perhaps SFINAE is one of them. I haven't used templates
in D enough to know for sure. Definitely worth discussing though IMO.
Anything that reduces the complexity of D without sacrificing expressive
power is a good thing.
-Craig

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.

How do I know if I'm using SFINAE or not? :-)
Seriously, I might be using it. I'm not sure. I'm not sure how to go
about checking. And that in and of itself seems like an undesirable
quality.
I will say that I have most definitely been bitten by errors that came
from failure to instantiate the template I thought I was instantiating
(most often due to IFTI failures). These things can usually be debugged
by switching the code I suspect to specify all template arguments. Then
I'll get the sensible error telling me why it doesn't match.
Also I've had bugs from the is-expressions not getting triggered because
I had a typo in the is-expression which wasn't a syntax error. Not sure
how the compiler could help there, though.
--bb

How do I know if I'm using SFINAE or not? :-)
Seriously, I might be using it. I'm not sure. I'm not sure how to go
about checking. And that in and of itself seems like an undesirable
quality.

Indeed!

I will say that I have most definitely been bitten by errors that came
from failure to instantiate the template I thought I was instantiating
(most often due to IFTI failures). These things can usually be debugged
by switching the code I suspect to specify all template arguments. Then
I'll get the sensible error telling me why it doesn't match.

Tuples hurt you here, because if you specify some Tuple template as a
"last resort" template, you can end up using it for things you thought
you'd handled. Or, at least, I think that maybe that's the case...with
SFINAE, it's hard to know for sure.

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++?

Here's a classic example of how SFINAE makes things hard. Look at the
code below. You'd expect the static assert to fail, right? Give you an
error message at the right location, and point you towards your bug?
Nope.
BEGIN CODE
import std.stdio;
template foo(TPL...)
{
static assert(false);
}
void main()
{
int i;
foo!(i)();
}
END CODE
Here's what the compiler actually says:
sfinae.d(3): template sfinae.foo(TPL...) is not a function template
sfinae.d(11): template sfinae.foo(TPL...) cannot deduce template
function from argument types !(i)()
Not even a mention of the real problem. Now imagine that you are using
non-trivial templates!
Russ

It looks like your first compiler error is correct... There is no function.

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++?

Here's a classic example of how SFINAE makes things hard. Look at the
code below. You'd expect the static assert to fail, right? Give you an
error message at the right location, and point you towards your bug?
Nope.
BEGIN CODE
import std.stdio;
template foo(TPL...)
{
static assert(false);
}
void main()
{
int i;
foo!(i)();
}
END CODE
Here's what the compiler actually says:
sfinae.d(3): template sfinae.foo(TPL...) is not a function template
sfinae.d(11): template sfinae.foo(TPL...) cannot deduce template
function from argument types !(i)()
Not even a mention of the real problem. Now imagine that you are using
non-trivial templates!
Russ

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.

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#Constraininghttp://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

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#Constraininghttp://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

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

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

If D could load specializations in another module, generalized traits could be
done in D. In fact, I'd argue that SFINAE would hide bugs in user-supplied
template code.

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

is a vector 2 could be done with an interface? The rest of the examples
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

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?

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.

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

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>

"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>

"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

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.

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
...

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
...

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.