digitalmars.D - Template constraints
- Andrei Alexandrescu (20/20) Feb 14 2015 There's been recurring discussion about failing constraints not
- Tobias Pankrath (17/38) Feb 14 2015 I agree, but also for function should conditions that do not
- Andrei Alexandrescu (2/15) Feb 14 2015 That would impact cross-module overloading. -- Andrei
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (6/10) Feb 14 2015 There was talk about enabling IFTI for constructors. If that is
- Xinok (23/44) Feb 14 2015 I've done this myself for the same reason. I may split up the
- Atila Neves (7/28) Feb 15 2015 Even then this "hides" some errors and debugging isn't easy
- Steven Schveighoffer (33/53) Feb 16 2015 Wait, isn't this OK?
- Nick Treleaven (9/24) Feb 19 2015 OK, so the idea might not be appropriate for types. What about for
- Chris Williams (10/31) Feb 17 2015 This seems like a lot of manual labor to cover a compiler
There's been recurring discussion about failing constraints not
generating nice error messages.
void fun(T)(T x) if (complicated_condition) { ... }
struct Type(T)(T x) if (complicated_condition) { ... }
If complicated_condition is not met, the symbol simply disappears and
the compiler error message just lists is as a possible, but not viable,
candidate.
I think one simple step toward improving things is pushing the condition
in a static_assert inside type definitions:
void fun(T)(T x) if (complicated_condition) { ... } // no change
struct Type(T)(T x)
{
static assert(complicated_condition, "Informative message.");
...
}
This should improve error messages for types (only). The rationale is
that it's okay for types to refuse compilation because types, unlike
functions, don't overload. The major reason for template constraints in
functions is allowing for good overloading.
Andrei
Feb 14 2015
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei
Alexandrescu wrote:
There's been recurring discussion about failing constraints not
generating nice error messages.
void fun(T)(T x) if (complicated_condition) { ... }
struct Type(T)(T x) if (complicated_condition) { ... }
If complicated_condition is not met, the symbol simply
disappears and the compiler error message just lists is as a
possible, but not viable, candidate.
I think one simple step toward improving things is pushing the
condition in a static_assert inside type definitions:
void fun(T)(T x) if (complicated_condition) { ... } // no change
struct Type(T)(T x)
{
static assert(complicated_condition, "Informative message.");
...
}
This should improve error messages for types (only). The
rationale is that it's okay for types to refuse compilation
because types, unlike functions, don't overload. The major
reason for template constraints in functions is allowing for
good overloading.
Andrei
I agree, but also for function should conditions that do not
effect overloading go into static asserts.
For example if I were to write an algorithm that works with
forward ranges and can be optimized for random access ranges but
needs assignable elements in any case:
void foo(R)(R r) if(isForwardRange!R && !isRandomAccessRange!R)
{
static assert(hasAssignableElements!R, "informative error
msg");
}
void foo(R)(R r) if(isRandomAccessRange!R)
{
static assert(hasAssignableElements!R, "informative error
msg");
}
Feb 14 2015
On 2/14/15 9:06 AM, Tobias Pankrath wrote:
I agree, but also for function should conditions that do not effect
overloading go into static asserts.
For example if I were to write an algorithm that works with forward
ranges and can be optimized for random access ranges but needs
assignable elements in any case:
void foo(R)(R r) if(isForwardRange!R && !isRandomAccessRange!R)
{
static assert(hasAssignableElements!R, "informative error msg");
}
void foo(R)(R r) if(isRandomAccessRange!R)
{
static assert(hasAssignableElements!R, "informative error msg");
}
That would impact cross-module overloading. -- Andrei
Feb 14 2015
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei Alexandrescu wrote:... This should improve error messages for types (only). The rationale is that it's okay for types to refuse compilation because types, unlike functions, don't overload.There was talk about enabling IFTI for constructors. If that is done, some types _will_ overload. But for the remaining ones (i.e. those that we don't want to overloadable), I think it's a good strategy.
Feb 14 2015
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei
Alexandrescu wrote:
There's been recurring discussion about failing constraints not
generating nice error messages.
void fun(T)(T x) if (complicated_condition) { ... }
struct Type(T)(T x) if (complicated_condition) { ... }
If complicated_condition is not met, the symbol simply
disappears and the compiler error message just lists is as a
possible, but not viable, candidate.
I think one simple step toward improving things is pushing the
condition in a static_assert inside type definitions:
void fun(T)(T x) if (complicated_condition) { ... } // no change
struct Type(T)(T x)
{
static assert(complicated_condition, "Informative message.");
...
}
This should improve error messages for types (only). The
rationale is that it's okay for types to refuse compilation
because types, unlike functions, don't overload. The major
reason for template constraints in functions is allowing for
good overloading.
Andrei
I've done this myself for the same reason. I may split up the
condition into multiple 'static assert' statements which gives a
more specific error message. However, I wonder if there's a
better solution that we can incorporate in to D. The trouble with
template constraints is that, if you have complex conditions,
there's no easy way to fall back to a default state. You would
have to duplicate all the conditions and write "not this and not
this and not this and ...".
Template specializations can fall back to a default state, but
not template constraints. So what if we were to add a feature
that would allow us to do just that?
void test(Range)(Range r) if(isRandomAccessRange!Range)
{
...
}
void test(Range)(Range r) default
{
static assert(false, "descriptive error message");
}
I'm not claiming this is a better solution; I'm simply putting
the idea out there.
Feb 14 2015
Even then this "hides" some errors and debugging isn't easy
(figuring out why the template constraint failed). I've been
planning on creating a DIP addressing this for ages, I should
probably get around to that.
Atila
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei
Alexandrescu wrote:
There's been recurring discussion about failing constraints not
generating nice error messages.
void fun(T)(T x) if (complicated_condition) { ... }
struct Type(T)(T x) if (complicated_condition) { ... }
If complicated_condition is not met, the symbol simply
disappears and the compiler error message just lists is as a
possible, but not viable, candidate.
I think one simple step toward improving things is pushing the
condition in a static_assert inside type definitions:
void fun(T)(T x) if (complicated_condition) { ... } // no change
struct Type(T)(T x)
{
static assert(complicated_condition, "Informative message.");
...
}
This should improve error messages for types (only). The
rationale is that it's okay for types to refuse compilation
because types, unlike functions, don't overload. The major
reason for template constraints in functions is allowing for
good overloading.
Andrei
Feb 15 2015
On 2/14/15 12:00 PM, Andrei Alexandrescu wrote:
There's been recurring discussion about failing constraints not
generating nice error messages.
void fun(T)(T x) if (complicated_condition) { ... }
struct Type(T)(T x) if (complicated_condition) { ... }
If complicated_condition is not met, the symbol simply disappears and
the compiler error message just lists is as a possible, but not viable,
candidate.
I think one simple step toward improving things is pushing the condition
in a static_assert inside type definitions:
void fun(T)(T x) if (complicated_condition) { ... } // no change
struct Type(T)(T x)
{
static assert(complicated_condition, "Informative message.");
...
}
This should improve error messages for types (only). The rationale is
that it's okay for types to refuse compilation because types, unlike
functions, don't overload. The major reason for template constraints in
functions is allowing for good overloading.
Andrei
Wait, isn't this OK?
struct S(T) if(is(T == int))
{
...
}
struct S(T) if(is(T == double))
{
...
}
I mean we could do it like this:
struct S(T)
{
static if(is(T == int))
{
... // int mode
}
else static if(is(T == double))
{
... // double mode
}
else static assert(0);
}
but that defeats the purpose of being able to split the "int mode" stuff
from the "double mode" stuff. They may even be in multiple modules.
Is this not "overloading" of types? I don't think this should be frowned
upon.
I think instead of this, we should try and just make the messages
better. Note that something like you are suggesting requires much
rewriting of code.
Have you considered something like this?
forum.dlang.org/post/m4nnrk$1ml5$1 digitalmars.com
-Steve
Feb 16 2015
On 16/02/2015 19:31, Steven Schveighoffer wrote:Wait, isn't this OK? struct S(T) if(is(T == int)) { ... } struct S(T) if(is(T == double)) { ... }...They may even be in multiple modules. Is this not "overloading" of types? I don't think this should be frowned upon.OK, so the idea might not be appropriate for types. What about for methods though - if a method doesn't have overloads, static assert might be better than a constraint. Even where there are overloads, (part of) the constraint may be OK to push into static assert instead for better error messages.I think instead of this, we should try and just make the messages better. Note that something like you are suggesting requires much rewriting of code.True, but until the compiler improves perhaps we could use this technique for methods e.g. in new code.
Feb 19 2015
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei
Alexandrescu wrote:
There's been recurring discussion about failing constraints not
generating nice error messages.
void fun(T)(T x) if (complicated_condition) { ... }
struct Type(T)(T x) if (complicated_condition) { ... }
If complicated_condition is not met, the symbol simply
disappears and the compiler error message just lists is as a
possible, but not viable, candidate.
I think one simple step toward improving things is pushing the
condition in a static_assert inside type definitions:
void fun(T)(T x) if (complicated_condition) { ... } // no change
struct Type(T)(T x)
{
static assert(complicated_condition, "Informative message.");
...
}
This should improve error messages for types (only). The
rationale is that it's okay for types to refuse compilation
because types, unlike functions, don't overload. The major
reason for template constraints in functions is allowing for
good overloading.
Andrei
This seems like a lot of manual labor to cover a compiler
limitation that is going to affect not just Phobos, but every D
project which uses constraints (or template type specialization?)
instead of interfaces. Ideally, the compiler would be able to
say, "Well the function name and the parameter list exactly match
these possibilities, so let's run through each constraint applied
in the set of possibilities and explicitly dump the boolean
result for each constraint."
Feb 17 2015









Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> 